#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <math.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/Separator.h>
#include <Xm/CascadeB.h>
#include <Xm/MessageB.h>
#include <Xm/DialogS.h>
#include <Xm/SeparatoG.h>
#include <Xm/PanedW.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/RowColumn.h>
#include <Xm/Frame.h>
#include <Xm/Label.h>
#include <Xm/MainW.h>
#include <Xm/ArrowB.h>
#include <X11/Shell.h>
#include <assert.h>

#define PI M_PI
#ifndef SQR
#define SQR(x)      ((x)*(x))
#endif /* SQR */
#ifndef MAX
#define MAX(a,b)    ((a)>(b)?(a):(b))
#endif /* MAX */
#ifndef MIN
#define MIN(a,b)    ((a)<(b)?(a):(b))
#endif /* MIN */


/*
 * Konstante
 */
#define g                  9.81

#define m                  1.0
#define l                  1.0
#define deltaT             0.005
#define ALPHA0            55.0*(PI/180.0)
#define ALPHA_DOT0         1.5
#define A0                 5.0
#define A1             50000.0

#define X_SIZE           900
#define Y_SIZE           100
#define X_SIZE_SD        280          /* Breite SetDefaults-Dialog */
#define Y_SIZE_SD        183          /* Hoehe SetDefaults-Dialog */
#define X_SIZE_AB        280          /* Breite About-"Bitte Warten" */
#define Y_SIZE_AB        83          /* Hoehe About-"Bitte Warten" */
#define Xscale            90.0        /* for W_core_pendel */
#define Yscale            90.0        /* for W_core_pendel */
#define PERIOD_SOME        4          /* Dauer zwischen Pendel-Updates */
#define ANGLE_DELTA_X      0.5

/*
 * Diverses anderes
 */
#define PENDEL_FRACTION 20

#define FONT_NORMAL       "font_normal"
#define FONT_NORMAL_NAME  "fixed"
#define FONT_BIG          "font_big"
#define FONT_BIG_NAME     "-*-helvetica-*-r-*--*-240-*-*-*-*-iso8859-1"


/*
 * Variablen fuer balance
 */
#define NB               0
#define NM               1
#define NS               2
#define ZE               3
#define PS               4 
#define PM               5
#define PB               6
#define NRANGES          7            /* Werte von NB, NM, ... */

#define ALPHA            range[0].value
#define ALPHA_DOT        range[1].value
#define A                range[2].value
#define ALPHA_RANGE      0
#define ALPHA_DOT_RANGE  1
#define A_RANGE          2

#define Bumper_alphaDot  0.5
#define Bumper_alpha     10.0*(PI/180.0)

typedef struct _Bound {
    double lower;
    double upper;
} Bound;

typedef struct _Rule {
    int alpha;                       /* wenn alpha == ... und */
    int alphaDot;                    /* alphaDot == ... dann */
    int a;                           /* a = ... */
} Rule;

Rule rule[]={            /* wenn ... und ... dann ... */
    { PM, ZE, PM },
    { PS, PS, PM },
    { PS, NS, ZE },
    { NM, ZE, NM },
    { NS, NS, NM },
    { NS, PS, ZE },
    { ZE, ZE, ZE },
};
#define NRULES           (sizeof(rule)/sizeof(Rule))

Bound alpha_mbounds = { -30.0, 210.0 };
Bound alpha_bound[NRANGES] = {
    { -30.0,  30.0 },           /* /\             */
    {   0.0,  60.0 },           /*   /\           */
    {  30.0,  90.0 },           /*     /\         */
    {  60.0, 120.0 },           /*       /\       */
    {  90.0, 150.0 },           /*         /\     */
    { 120.0, 180.0 },           /*           /\   */
    { 150.0, 210.0 }            /*             /\ */
};
Bound alphaDot_mbounds = { -5.0, 5.0 };
Bound alphaDot_bound[NRANGES] = {
    { -5.0, -1.0 },             /* /\             */
    { -3.0, -1.0 },             /*   /\           */
    { -2.0,  1.0 },             /*     /\         */
    { -0.5,  0.5 },             /*       /\       */
    { -1.0,  2.0 },             /*         /\     */
    {  1.0,  3.0 },             /*           /\   */
    {  1.0,  5.0 },             /*             /\ */
};
Bound a_mbounds = { -7.0, 7.0 };
Bound a_bound[NRANGES] = {
    { -7.0, -5.0 },             /* /\             */
    { -5.0, -3.0 },             /*   /\           */
    { -3.0, -1.0 },             /*     /\         */
    { -1.0,  1.0 },             /*       /\       */
    {  1.0,  3.0 },             /*         /\     */
    {  3.0,  5.0 },             /*           /\   */
    {  5.0,  7.0 },             /*             /\ */
};
double Fa;
double Fg;
double xpos,oldxpos;
int angle_tick;
double angle_xpos, angle_oldxpos;
double angle_ypos, angle_oldypos;
double alpha0,alphaDot0;
double a0;                           /* max. Beschleuningung */
char *range_name[7] = { "NB","NM","NS","ZE","PS","PM","PB" };


/*
 *  Variablen fuer X/Motif
 */
typedef struct _Value {
    Widget     W_form;
    Widget       W_label;
    Widget       W_value;
    double         value;
} Value;

typedef struct _Range {
    Widget W_frame;
    Widget   W_box;         /* rowcolumn */
    Widget     W_title;
    char*        title;
    Widget     W_sep1;
    Value      value[NRANGES];
    Widget     W_sep2;
    Widget     W_core_values;
    GC         gc_core_values;
    Widget     W_exact;
    double       exact;
    double       oldexact;
} Range;

Widget W_toplevel;
Widget   W_main;
Widget     W_rc_outer;
Widget       W_menubar;
Widget         W_file_menu;
Widget           W_file_foobar;
Widget             W_reset_menuitem;
Widget             W_setdefaults_menuitem;
Widget               W_sd_dialog; 
Widget                 W_sd_rc;
Widget                   W_sd_title_form;
Widget                     W_sd_title;
Widget                   W_sd_sep1;
Widget                   W_sd_control_rc;
Widget                     W_sd_alpha0_form;
Widget                       W_sd_alpha0_label;
Widget                       W_sd_alpha0_text;
Widget                         W_sd_alpha0_Error;
Widget                     W_sd_alphaDot0_form;
Widget                       W_sd_alphaDot0_label;
Widget                       W_sd_alphaDot0_text;
Widget                     W_sd_a0_form;
Widget                       W_sd_a0_label;
Widget                       W_sd_a0_text;
Widget                         W_sd_a0_Error;
Widget                   W_sd_sep2; 
Widget                   W_sd_action_form;
Widget                     W_sd_ok;
Widget                     W_sd_cancel;
Widget             W_about_menuitem;
Widget               W_ab_dialog;
Widget                 W_ab_frame;
Widget                   W_ab_rc;
Widget                     W_ab_form;
Widget                       W_ab_pleasewait;
Widget             W_sep_menuitem;
Widget             W_quit_menuitem;
Widget       W_title_form;
Widget         W_title;
Widget       W_sep1;
Widget       W_rc_main;
Widget         W_form_pendel;
Widget           W_push_left;
Widget           W_core_pendel;
Widget           W_push_right;
Widget         W_core_angle;
Widget         W_form_ranges;
Range            range[3];
Widget         W_form_exacts;
Widget       W_sep2;
Widget       W_form_bottom;
Widget         W_startstop;
Widget         W_step;
Widget         W_quit;

XtAppContext app_context;

XFontStruct *font;
XmFontList fontlist;

Colormap cmap;
GC gc_core_pendel;
GC gc_core_angle;
unsigned long black, white;
XColor     col_red;
XColor     col_yellow;


/*
 * Prototypen
 */
double balance(double alpha, double alphaDot);
void update_widgets(int all);
void update_values(void);
void periodicTO(Widget w);
void stepCB(Widget w, XtPointer client_data, XtPointer call_data);
void quitCB(Widget w, XtPointer client_data, XtPointer call_data);
void startstopCB(Widget w, XtPointer client_data, XtPointer call_data);
void pushCB(Widget w, XtPointer client_data, XtPointer call_data);
void aboutCB(Widget w, XtPointer client_data, XtPointer call_data);
void aboutAlarm(int sig);
void setdefaultsCB(Widget w, XtPointer client_data, XtPointer call_data);
void sd_okCB(Widget w, XtPointer client_data, XtPointer call_data);
void sd_cancelCB(Widget w, XtPointer client_data, XtPointer call_data);
void resetCB(Widget w, XtPointer client_data, XtPointer call_data);
void init(int argc, char *argv[]);

/*************************************************************************/
double balance(double alpha, double alphaDot)
{
    double max,mid;
    int i;

    range[ALPHA_RANGE].exact     = alpha;
    range[ALPHA_RANGE].oldexact  = alpha;
    range[ALPHA_DOT_RANGE].exact = alphaDot;
    
    /* Gewichte von alpha ausrechnen */
    for(i=0;i<NRANGES;i++){
	if((alpha_bound[i].upper > alpha) && (alpha > alpha_bound[i].lower)){
	    mid = (alpha_bound[i].upper+alpha_bound[i].lower)/2.0;
	    if(alpha>mid){
		/* linke Haelfte */
		ALPHA[i].value
		  = 1.0-(alpha-mid)/(alpha_bound[i].upper-mid);
	    }else{
		/* rechte Haelfte */
		ALPHA[i].value
		  = (alpha-alpha_bound[i].lower)/(mid-alpha_bound[i].lower);
	    }
	}else{
	    ALPHA[i].value = 0.0;
	}
    }

    /* Gewichte von alphaDot ausrechnen */
    for(i=0;i<NRANGES;i++){
	if((alphaDot_bound[i].upper > alphaDot) &&
	   (alphaDot > alphaDot_bound[i].lower)){
	    mid = (alphaDot_bound[i].upper+alphaDot_bound[i].lower)/2.0; 
	    if(alphaDot>mid){
		/* rechte Haelfte */
		ALPHA_DOT[i].value
		  = 1.0-(alphaDot-mid)/(alphaDot_bound[i].upper-mid);
	    }else{
		/* linke Haelfte */
		ALPHA_DOT[i].value
		  = (alphaDot-alphaDot_bound[i].lower)
		    /(mid-alphaDot_bound[i].lower);
	    }
	}else{
	    ALPHA_DOT[i].value = 0.0;
	}
    }

    /* Regeln anwenden */
    for(i=0;i<NRULES;i++){
	A[i].value = 0.0;
    }
    for(i=0;i<NRULES;i++){
	A[rule[i].a].value =
	  MAX(A[rule[i].a].value,
	      MIN(ALPHA[rule[i].alpha].value,
		  ALPHA_DOT[rule[i].alphaDot].value));
    }

    /* Mittelwert der A's berechnen */
    max=0.0;
    for(i=0;i<NRANGES;i++){
	max = max + (i-(NRANGES/2))*A[i].value;
    }

    range[A_RANGE].exact = -max;

    return -max;
}

/*************************************************************************/
void periodicTO(Widget w)
{
    if(!XtIsSensitive(W_step)){
	update_values();
	update_widgets(0);
	XtAppAddTimeOut(app_context,PERIOD_SOME,(XtTimerCallbackProc)periodicTO,
			(XtPointer)0);
    }
}

/*************************************************************************/
void stepCB(Widget w, XtPointer client_data, XtPointer call_data)
{
    update_values();
    update_widgets(1);
}

/*************************************************************************/
void setdefaultsCB(Widget widget, XtPointer client_data, XtPointer call_data)
{
    char str[256];
    XmString xstr;
    Position x,y;
    Dimension w,h;

    if(!W_sd_dialog){
	XtVaGetValues(W_main,
		      XmNwidth,&w,
		      XmNheight,&h,
		      XmNx,&x,
		      XmNy,&y,
		      NULL);
    
	W_sd_dialog
	  = XtVaCreateManagedWidget("sd_dialog",
				    xmDialogShellWidgetClass,
				    W_toplevel,
				    XmNx,x+(w-X_SIZE_SD)/2,
				    XmNy,y+(h-Y_SIZE_SD)/2,
				    NULL);

	W_sd_rc
	  = XtVaCreateManagedWidget("sd_rc",
				    xmRowColumnWidgetClass,
				    W_sd_dialog,
				    XmNwidth, X_SIZE_SD,
				    XmNheight, Y_SIZE_SD,
				    NULL);

	{
	    /* Titel */
	    W_sd_title_form
	      = XtVaCreateManagedWidget("sd_title_form",
					xmFormWidgetClass,
					W_sd_rc,
					XmNfractionBase,1,
					NULL);

	    xstr=XmStringCreate("Set Defaults",FONT_BIG);
	    W_sd_title
	      = XtVaCreateManagedWidget("sd_title",
					xmLabelWidgetClass,
					W_sd_title_form,
					XmNlabelString,xstr,
					XmNfontList,fontlist,
					XmNalignment,XmALIGNMENT_CENTER,
					XmNleftAttachment,XmATTACH_POSITION,
					XmNleftPosition,0,
					XmNrightAttachment,XmATTACH_POSITION,
					XmNrightPosition,1,
					NULL);
	    XmStringFree(xstr);
	}
	W_sd_sep1
	  = XtVaCreateManagedWidget("sd_sep1",
				    xmSeparatorWidgetClass,
				    W_sd_rc,
				    NULL);
	{
	    /* Control */
       
	    W_sd_control_rc
	      = XtVaCreateManagedWidget("sd_control_rc",
					xmRowColumnWidgetClass,
					W_sd_rc,
					XmNfontList,fontlist,
					NULL);

	    {
		/* alpha0 */
		W_sd_alpha0_form
		  = XtVaCreateManagedWidget("sd_alpha0_form",
					    xmFormWidgetClass,
					    W_sd_control_rc,
					    NULL);
	    
		xstr=XmStringCreate("Alpha0: ",FONT_NORMAL);
		W_sd_alpha0_label
		  = XtVaCreateManagedWidget("sd_alpha0_label",
					    xmLabelWidgetClass,
					    W_sd_alpha0_form,
					    XmNlabelString,xstr,
					    XmNfontList,fontlist,
					    XmNalignment,XmALIGNMENT_BEGINNING,
					    XmNleftAttachment,XmATTACH_FORM,
					    XmNtopAttachment,XmATTACH_FORM,
					    XmNbottomAttachment,XmATTACH_FORM,
					    NULL);
		XmStringFree(xstr);
	    
		sprintf(str,"%6.2f",alpha0/PI*180.0);
		W_sd_alpha0_text
		  = XtVaCreateManagedWidget("sd_alpha0_text",
					    xmTextFieldWidgetClass,
					    W_sd_alpha0_form,
					    XmNvalue,str,
					    XmNfontList,fontlist,
					    XmNalignment,XmALIGNMENT_END,
					    XmNleftAttachment,XmATTACH_WIDGET,
					    XmNleftWidget,W_sd_alpha0_label,
					    XmNrightAttachment,XmATTACH_FORM,
					    NULL);
	    }
	    {
		/* alphaDot0 */
		W_sd_alphaDot0_form
		  = XtVaCreateManagedWidget("sd_alphaDot0_form",
					    xmFormWidgetClass,
					    W_sd_control_rc,
					    NULL);
	    
		xstr=XmStringCreate("AlphaDot0: ",FONT_NORMAL);
		W_sd_alphaDot0_label
		  = XtVaCreateManagedWidget("sd_alphaDot0_label",
					    xmLabelWidgetClass,
					    W_sd_alphaDot0_form,
					    XmNlabelString,xstr,
					    XmNfontList,fontlist,
					    XmNalignment,XmALIGNMENT_BEGINNING,
					    XmNleftAttachment,XmATTACH_FORM,
					    XmNtopAttachment,XmATTACH_FORM,
					    XmNbottomAttachment,XmATTACH_FORM,
					    NULL);
		XmStringFree(xstr);
	    
		sprintf(str,"%6.2f",alphaDot0);
		W_sd_alphaDot0_text
		  = XtVaCreateManagedWidget("sd_alphaDot0_text",
					    xmTextWidgetClass,
					    W_sd_alphaDot0_form,
					    XmNvalue,str,
					    XmNfontList,fontlist,
					    XmNalignment,XmALIGNMENT_END,
					    XmNleftAttachment,XmATTACH_WIDGET,
					    XmNleftWidget,W_sd_alphaDot0_label,
					    XmNrightAttachment,XmATTACH_FORM,
					    NULL);
	    }
	    {
		/* a0 */
		W_sd_a0_form
		  = XtVaCreateManagedWidget("sd_a0_form",
					    xmFormWidgetClass,
					    W_sd_control_rc,
					    NULL);
	    
		xstr=XmStringCreate("a0: ",FONT_NORMAL);
		W_sd_a0_label
		  = XtVaCreateManagedWidget("sd_a0_label",
					    xmLabelWidgetClass,
					    W_sd_a0_form,
					    XmNlabelString,xstr,
					    XmNfontList,fontlist,
					    XmNalignment,XmALIGNMENT_BEGINNING,
					    XmNleftAttachment,XmATTACH_FORM,
					    XmNtopAttachment,XmATTACH_FORM,
					    XmNbottomAttachment,XmATTACH_FORM,
					    NULL);
		XmStringFree(xstr);
	    
		sprintf(str,"%6.2f",a0);
		W_sd_a0_text
		  = XtVaCreateManagedWidget("sd_a0_text",
					    xmTextWidgetClass,
					    W_sd_a0_form,
					    XmNvalue,str,
					    XmNfontList,fontlist,
					    XmNalignment,XmALIGNMENT_END,
					    XmNleftAttachment,XmATTACH_WIDGET,
					    XmNleftWidget,W_sd_a0_label,
					    XmNrightAttachment,XmATTACH_FORM,
					    NULL);
	    }
	}
	W_sd_sep2
	  = XtVaCreateManagedWidget("sd_sep2",
				    xmSeparatorWidgetClass,
				    W_sd_rc,
				    NULL);
	{
	    /* Action */
	    W_sd_action_form
	      = XtVaCreateManagedWidget("sd_action_form",
					xmFormWidgetClass,
					W_sd_rc,
					XmNfractionBase,5,
					NULL);

	    xstr=XmStringCreate("OK",FONT_NORMAL);
	    W_sd_ok
	      = XtVaCreateManagedWidget("sd_ok",
					xmPushButtonWidgetClass,
					W_sd_action_form,
					XmNfontList,fontlist,
					XmNlabelString,xstr,
					XmNleftAttachment,XmATTACH_POSITION,
					XmNleftPosition,1,
					XmNrightAttachment,XmATTACH_POSITION,
					XmNrightPosition,2,
					NULL);
	    XmStringFree(xstr);
	    XtAddCallback(W_sd_ok,XmNactivateCallback,sd_okCB,NULL);

	    xstr=XmStringCreate("Cancel",FONT_NORMAL);
	    W_sd_cancel
	      = XtVaCreateManagedWidget("sd_cancel",
					xmPushButtonWidgetClass,
					W_sd_action_form,
					XmNfontList,fontlist,
					XmNlabelString,xstr,
					XmNleftAttachment,XmATTACH_POSITION,
					XmNleftPosition,3,
					XmNrightAttachment,XmATTACH_POSITION,
					XmNrightPosition,4,
					NULL);
	    XmStringFree(xstr);
	    XtAddCallback(W_sd_cancel,XmNactivateCallback,sd_cancelCB,NULL);
	}
	
	XtRealizeWidget(W_sd_dialog);
    }
    
    XtPopup(W_sd_dialog,XtGrabNone);
}   


/*************************************************************************/
void sd_okCB(Widget w, XtPointer client_data, XtPointer call_data)
{
    char *txt;
    XmString xstr;
    double new_alpha0;
    double new_alphaDot0;
    double new_a0;

    txt = XmTextGetString(W_sd_alpha0_text);
    new_alpha0 = atof(txt)/180.0*PI;
    XtFree(txt);
    
    txt = XmTextGetString(W_sd_alphaDot0_text);
    new_alphaDot0 = atof(txt);
    XtFree(txt);
    
    txt = XmTextGetString(W_sd_a0_text);
    new_a0 = atof(txt);
    XtFree(txt);

    if(new_alpha0<0.0 || new_alpha0>PI){
	/* FEHLER: alpha0 */
	char str[256];
	
	XBell(XtDisplay(W_toplevel),100);
	
	sprintf(str,"%6.2f",alpha0/PI*180.0);
	XmTextSetString(W_sd_alpha0_text,str);
	
	xstr=XmStringCreateLtoR("FEHLER:\n0 <= alpha0 <= PI",FONT_NORMAL);
	W_sd_alpha0_Error
	  = XmCreateMessageDialog(W_sd_alpha0_text,
				  "sd_alpha0_Error",
				  NULL,0);
	XtVaSetValues(W_sd_alpha0_Error,
		      XmNdialogType,XmDIALOG_INFORMATION,
		      XmNmessageString,xstr,
		      NULL);
	XmStringFree(xstr);
	XtUnmanageChild(XmMessageBoxGetChild(W_sd_alpha0_Error,
					     XmDIALOG_CANCEL_BUTTON));
	XtUnmanageChild(XmMessageBoxGetChild(W_sd_alpha0_Error,
					     XmDIALOG_HELP_BUTTON));
	XtManageChild(W_sd_alpha0_Error);
	XtPopup(XtParent(W_sd_alpha0_Error),XtGrabExclusive);
    }else if(new_a0<=0.0 || new_a0>25.0){
	/* FEHLER: a0 */
	char str[256];
	
	XBell(XtDisplay(W_toplevel),100);
	
	sprintf(str,"%6.2f",a0);
	XmTextSetString(W_sd_a0_text,str);
	
	xstr=XmStringCreateLtoR("FEHLER:\n0 < a0 <= 25",FONT_NORMAL);
	W_sd_a0_Error
	  = XmCreateMessageDialog(W_sd_a0_text,
				  "sd_a0_Error",
				  NULL,0);
	XtVaSetValues(W_sd_a0_Error,
		      XmNdialogType,XmDIALOG_ERROR,
		      XmNmessageString,xstr,
		      NULL);
	XmStringFree(xstr);
	XtUnmanageChild(XmMessageBoxGetChild(W_sd_a0_Error,
					     XmDIALOG_CANCEL_BUTTON));
	XtUnmanageChild(XmMessageBoxGetChild(W_sd_a0_Error,
					     XmDIALOG_HELP_BUTTON));
	XtManageChild(W_sd_a0_Error);
	XtPopup(XtParent(W_sd_a0_Error),XtGrabExclusive);
    }else{
	alpha0    = new_alpha0;
	alphaDot0 = new_alphaDot0;
	a0        = new_a0;
	
	XtPopdown(W_sd_dialog);

	resetCB(0,0,0);
	update_widgets(1);
    }
}

/*************************************************************************/
void sd_cancelCB(Widget w, XtPointer client_data, XtPointer call_data)
{
    if(W_sd_alpha0_Error){
	XtUnmanageChild(W_sd_alpha0_Error);
	W_sd_alpha0_Error=NULL;
    }
    if(W_sd_a0_Error){
	XtUnmanageChild(W_sd_a0_Error);
	W_sd_a0_Error=NULL;
    }
    XtPopdown(W_sd_dialog);
}

/*************************************************************************/
void update_widgets(int all)
{
    int j;
    XmString xstr;
    char str[256];

    /*
     * pendel-Widget
     */
    {
	Dimension width;
	
	XtVaGetValues(W_core_pendel,
		      XmNwidth,&width,
		      NULL);

	XSetForeground(XtDisplay(W_core_pendel),gc_core_pendel,white);
	XDrawLine(XtDisplay(W_core_pendel),
		  XtWindow(W_core_pendel),
		  gc_core_pendel,
		  (int)oldxpos,
		  Y_SIZE,
		  (int)oldxpos+(int)(Xscale*cos(range[ALPHA_RANGE].oldexact)),
		  Y_SIZE-(int)(Yscale*sin(range[ALPHA_RANGE].oldexact)));

	XSetForeground(XtDisplay(W_core_pendel),gc_core_pendel,black);
	XDrawLine(XtDisplay(W_core_pendel),
		  XtWindow(W_core_pendel),
		  gc_core_pendel,
		  (int)xpos,
		  Y_SIZE,
		  (int)xpos+(int)(Xscale*cos(range[ALPHA_RANGE].exact)),
		  Y_SIZE-(int)(Yscale*sin(range[ALPHA_RANGE].exact)));
    }

    /*
     * angle-Widget
     */
    {
	Dimension width;

	XtVaGetValues(W_core_angle,
		      XmNwidth,&width,
		      NULL);

	if((int)angle_xpos>=width){
	    XClearWindow(XtDisplay(W_core_angle),XtWindow(W_core_angle));

	    XDrawLine(XtDisplay(W_core_angle),
		      XtWindow(W_core_angle),
		      gc_core_angle,
		      (int)1,Y_SIZE/2,
		      (int)(width-1),Y_SIZE/2);

	    angle_xpos      = ANGLE_DELTA_X;
	    angle_oldxpos   = 0.0;
	    angle_ypos      = Y_SIZE/2 + 0.97*Y_SIZE/2*cos(range[ALPHA_RANGE].exact);
	    angle_oldypos   = Y_SIZE/2 + 0.97*Y_SIZE/2*cos(range[ALPHA_RANGE].exact);
	}
	
	if(angle_tick++==(int)(1/ANGLE_DELTA_X)){
	    XSetForeground(XtDisplay(W_core_angle),gc_core_angle,black);

	    XDrawLine(XtDisplay(W_core_angle),
		      XtWindow(W_core_angle),
		      gc_core_angle,
		      (int)1,Y_SIZE/2,
		      (int)(width-1),Y_SIZE/2);

	    XDrawLine(XtDisplay(W_core_angle),
		      XtWindow(W_core_angle),
		      gc_core_angle,
		      (Position)angle_oldxpos,
		      (Position)angle_oldypos,
		      (Position)angle_xpos,
		      (Position)angle_ypos);

	    angle_oldxpos = angle_xpos;
	    angle_oldypos = angle_ypos;
	    angle_xpos += ANGLE_DELTA_X;
	    angle_ypos = Y_SIZE/2 + 0.97*Y_SIZE/2*cos(range[ALPHA_RANGE].exact);
	    
	    angle_tick=0;
	}
    }
    
    /*
     * 3 Ranges (alpha, alphaDot, a): Zahlenwerte
     */
    if(all){
	/* Viele Werte */
	for(j=0;j<3;j++){
	    int i;
	    
	    for(i=0;i<7;i++){
		sprintf(str,"%5.3f",range[j].value[i].value);
		xstr=XmStringCreate(str,FONT_NORMAL);
		XtVaSetValues(range[j].value[i].W_value,
			      XmNlabelString,xstr,
			      NULL);
		XmStringFree(xstr);
	    }
	}
    }
    {
	/* Gesamtwerte */
	static int exactcnt=0;

	if(all || exactcnt++>25){
	    for(j=0;j<3;j++){
		if(j==0){
		    sprintf(str,"%s = %4.1f°",range[j].title,range[j].exact/PI*180.0);
		}else{
		    sprintf(str,"%s =%6.3f",range[j].title,range[j].exact);
		}
		xstr=XmStringCreate(str,FONT_NORMAL);
		XtVaSetValues(range[j].W_exact,
			      XmNlabelString,xstr,
			      NULL);
		XmStringFree(xstr);
	    }

	    exactcnt=0;
	}
    }
    
    
    /*
     * 3 Ranges (alpha, alphaDot, a): Dreiecke
     */
    {
	static int tricnt=0;
	
	if(all || tricnt++>25){
	    for(j=0;j<3;j++){
		int i;
		Dimension width;
		double uppest,lowest,len;
		Bound (*bound)[NRANGES];
		Bound (*mbounds);
		
		XClearWindow(XtDisplay(range[j].W_core_values),
			     XtWindow(range[j].W_core_values));
		
		switch(j){
		  case 0:
		    bound   = &alpha_bound;
		    mbounds = &alpha_mbounds;
		    break;
		  case 1:
		    bound   = &alphaDot_bound;
		    mbounds = &alphaDot_mbounds;
		    break;
		  case 2:
		    bound   = &a_bound;
		    mbounds = &a_mbounds;
		    break;
		  default:
		    abort();
		};
		
		XtVaGetValues(range[j].W_core_values,
			      XmNwidth,&width,
			      NULL);
		
		lowest = (*mbounds).lower;
		uppest = (*mbounds).upper;
		len = uppest-lowest;
		
		for(i=0;i<NRANGES;i++){
		    int left,mid,right;
		    XPoint points[4];
		    
		    left  = (int)((((*bound)[i].lower) - lowest)/len*width);
		    right = (int)((((*bound)[i].upper) - lowest)/len*width);
		    mid   = (left+right)/2;
		    
		    XSetForeground(XtDisplay(range[j].W_core_values),
				   range[j].gc_core_values,
				   col_yellow.pixel);
		    points[0].x=(short)left +1;
		    points[0].y=(short)Y_SIZE;
		    points[1].x=(short)right -1;
		    points[1].y=(short)Y_SIZE;
		    points[2].x=(short)right-(mid-left)*range[j].value[i].value -1;
		    points[2].y=(short)Y_SIZE*(1-range[j].value[i].value);
		    points[3].x=(short)left+(mid-left)*range[j].value[i].value +1;
		    points[3].y=(short)Y_SIZE*(1-range[j].value[i].value);
		    XFillPolygon(XtDisplay(range[j].W_core_values),
				 XtWindow(range[j].W_core_values),
				 range[j].gc_core_values,
				 points,4,
				 Convex,CoordModeOrigin);
		}
		
		for(i=0;i<NRANGES;i++){
		    int left,mid,right;
		    
		    left  = (int)((((*bound)[i].lower) - lowest)/len*width);
		    right = (int)((((*bound)[i].upper) - lowest)/len*width);
		    mid   = (left+right)/2;
		    
		    XSetForeground(XtDisplay(range[j].W_core_values),
				   range[j].gc_core_values,black);
		    XDrawLine(XtDisplay(range[j].W_core_values),
			      XtWindow(range[j].W_core_values),
			      range[j].gc_core_values,
			      left,Y_SIZE,
			      mid,0);
		    XDrawLine(XtDisplay(range[j].W_core_values),
			      XtWindow(range[j].W_core_values),
			      range[j].gc_core_values,
			      mid,0,
			      right,Y_SIZE);
		}
		
		XSetForeground(XtDisplay(range[j].W_core_values),
			       range[j].gc_core_values,
			       col_red.pixel);
		XDrawLine(XtDisplay(range[j].W_core_values),
			  XtWindow(range[j].W_core_values),
			  range[j].gc_core_values,
			  (int)(((j==2?-1:1)*range[j].exact - lowest)/len*width),
			  0,
			  (int)(((j==2?-1:1)*range[j].exact - lowest)/len*width),
			  Y_SIZE);
	    }

	    tricnt=0;
	}
    }
}

/*************************************************************************/
void update_values(void)
{
    double *alpha    = &range[ALPHA_RANGE].exact;
    double *oldalpha = &range[ALPHA_RANGE].oldexact;
    double *alphaDot = &range[ALPHA_DOT_RANGE].exact;
    double Fres,rho,Fz,deltaAlpha;
    double a;

    *oldalpha = *alpha;
    oldxpos = xpos;

    a=balance(*alpha,*alphaDot);
    Fa = m*a*a0;

    /* Pendel-Verhalten nach Ch. Ziegaus */
    Fres        = sqrt(SQR(Fg) + SQR(Fa));
    rho         = *alpha - acos(Fa/Fres);
    Fz          = sin(rho) * Fres;
    deltaAlpha  = Fz/(2.0*m*l)*SQR(deltaT) + *alphaDot*deltaT;
    *alphaDot   = Fz/(m*l)*deltaT + *alphaDot;
    *alpha      = *alpha + deltaAlpha;
    xpos        = xpos + 0.5*a*SQR(deltaT)*A1;
    
    if(*alpha>PI){
	*alpha = PI;
	*alphaDot = 0.0;

	startstopCB(NULL,NULL,NULL);
    }
    if(*alpha<0){
	*alpha = 0;
	*alphaDot = 0.0;
	
	startstopCB(NULL,NULL,NULL);
    }
}

/*************************************************************************/
void resetCB(Widget w, XtPointer client_data, XtPointer call_data)
{
    Dimension width;
	
    XtVaGetValues(W_core_pendel,
		  XmNwidth,&width,
		  NULL);
    xpos = width/2;

    angle_tick=0;
    angle_xpos     = ANGLE_DELTA_X;
    angle_oldxpos  = 0.0;
    angle_ypos     = Y_SIZE/2 + 0.97*Y_SIZE/2*cos(range[ALPHA_RANGE].exact);
    angle_oldypos  = Y_SIZE/2 + 0.97*Y_SIZE/2*cos(range[ALPHA_RANGE].exact);

    range[ALPHA_RANGE].exact     = alpha0;
    range[ALPHA_DOT_RANGE].exact = alphaDot0;
    range[A_RANGE].exact         = 0.0;
    Fa = m*balance(range[ALPHA_RANGE].exact,range[ALPHA_DOT_RANGE].exact);
    Fg = m*g;

    if(!XtIsSensitive(W_step)){
	startstopCB(NULL,NULL,NULL);
    }

    XClearWindow(XtDisplay(W_core_pendel),XtWindow(W_core_pendel));
    
    XClearWindow(XtDisplay(W_core_angle),XtWindow(W_core_angle));
    XSetForeground(XtDisplay(W_core_angle),gc_core_angle,black);
    XDrawLine(XtDisplay(W_core_angle),
	      XtWindow(W_core_angle),
	      gc_core_angle,
	      (int)1,Y_SIZE/2,
	      (int)(width-1),Y_SIZE/2);

    update_widgets(1);
}

/*************************************************************************/
void aboutCB(Widget widget, XtPointer client_data, XtPointer call_data)
{
    Position x,y;
    Dimension w,h;
    XmString xstr;

    if(!W_ab_dialog){
	XtVaGetValues(W_main,
		      XmNwidth,&w,
		      XmNheight,&h,
		      XmNx,&x,
		      XmNy,&y,
		      NULL);
	
	xstr=XmStringCreateLtoR("Bitte warten!",FONT_NORMAL);
	W_ab_dialog
	  = XmCreateMessageDialog(W_toplevel,
				  "ab_dialog",
				  NULL,0);
	XtVaSetValues(W_ab_dialog,
		      XmNdialogType,XmDIALOG_ERROR,
		      XmNmessageString,xstr,
		      NULL);
	XmStringFree(xstr);
	XtUnmanageChild(XmMessageBoxGetChild(W_ab_dialog,
					     XmDIALOG_CANCEL_BUTTON));
	XtUnmanageChild(XmMessageBoxGetChild(W_ab_dialog,
					     XmDIALOG_HELP_BUTTON));
	XtRealizeWidget(W_ab_dialog);
	XtManageChild(W_ab_dialog);
    }
    XtPopup(XtParent(W_ab_dialog),XtGrabExclusive);

    signal(SIGALRM,aboutAlarm);
    alarm(5);

    system("mosaic http://rfhs1012.fh.uni-regensburg.de/usergroups/wwwki/FuzzyPendel/ &");
}

/*************************************************************************/
void aboutAlarm(int sig)
{
    XtPopdown(XtParent(W_ab_dialog));
}
	  
/*************************************************************************/
void quitCB(Widget w, XtPointer client_data, XtPointer call_data)
{
    exit(0);
}

/*************************************************************************/
void startstopCB(Widget w, XtPointer client_data, XtPointer call_data)
{
    XmString xstr;
    
    if(XtIsSensitive(W_step)){
	/* start */
	XtSetSensitive(W_step,False);
 
	xstr=XmStringCreate("Stop",FONT_NORMAL);
	XtVaSetValues(W_startstop,
		      XmNlabelString,xstr,
		      NULL);
	XmStringFree(xstr);

	XtAppAddTimeOut(app_context,PERIOD_SOME,(XtTimerCallbackProc)periodicTO,
			(XtPointer)0);
    }else{
	/* stop */
	XtSetSensitive(W_step,True);
	
	xstr=XmStringCreate("Start",FONT_NORMAL);
	XtVaSetValues(W_startstop,
		      XmNlabelString,xstr,
		      NULL);
	XmStringFree(xstr);

	update_widgets(1);
    }
}

/*************************************************************************/
void pushCB(Widget w, XtPointer client_data, XtPointer call_data)
{
    double *alpha    = &range[ALPHA_RANGE].exact;
    double *oldalpha = &range[ALPHA_RANGE].oldexact;
    double *alphaDot = &range[ALPHA_DOT_RANGE].exact;

    *oldalpha = *alpha;
    oldxpos = xpos;

    angle_oldypos=angle_ypos;
    
    if(client_data){
	/* Push to right */
	*alpha    -= Bumper_alpha;
	*alphaDot -= Bumper_alphaDot;
	
	if(*alpha < 0.0){
	    *alpha    = 0.0;
	    *alphaDot = 0.0;

	    startstopCB(NULL,NULL,NULL);
	}
    }else{
	/* Push to left */
	*alpha    += Bumper_alpha;
	*alphaDot += Bumper_alphaDot;

	if(*alpha>PI){
	    *alpha    = PI;
	    *alphaDot = 0.0;
	    
	    startstopCB(NULL,NULL,NULL);
	}
    }

    if(XtIsSensitive(W_step)){
	update_widgets(1);
    }else{
	update_widgets(0);
    }
}

/*************************************************************************/
void init(int argc, char *argv[])
{
    int i;

    /* Bereichs-Ueberschriften */
    range[0].title="alpha";
    range[1].title="alphaDot";
    range[2].title="a";

    for(i=0;i<NRANGES;i++){
	alpha_bound[i].lower = alpha_bound[i].lower*PI/180.0;
	alpha_bound[i].upper = alpha_bound[i].upper*PI/180.0;
    }
    alpha_mbounds.upper =    alpha_mbounds.upper*PI/180.0;
    alpha_mbounds.lower =    alpha_mbounds.lower*PI/180.0;

    /* alpha0 und alphaDot0 ueber Befehlszeile oder Defaults */
    if(argc>3){
	alpha0    = atof(argv[1])/180.0*PI;
	alphaDot0 = atof(argv[2]);
	a0        = atof(argv[3]);

	if(a0>25.0 || a0<=0.0){
	    fprintf(stderr,"a0 must be in ]0.0;25.0]\n");
	    exit(1);
	}	  
    }else{
	if(argc==1){
	    alpha0    = ALPHA0;
	    alphaDot0 = ALPHA_DOT0;
	    a0        = A0;
	}else{
	    fprintf(stderr,"Usage: %s alpha alphaDot a0\n",argv[0]);
	    fprintf(stderr,"Defaults are alpha    = %7.4f°\n",ALPHA0/PI*180.0);
	    fprintf(stderr,"             alphaDot = %7.4f\n",ALPHA_DOT0);
	    fprintf(stderr,"             a0       = %7.4f\n",A0);
	    exit(1);
	}
    }

    /* Anfangslage des Pendels, sollte ueber Dialog geregelt werden!!! */
    range[ALPHA_RANGE].exact     = alpha0;
    range[ALPHA_RANGE].oldexact  = alpha0;
    range[ALPHA_DOT_RANGE].exact = alphaDot0;
    range[A_RANGE].exact         = 0.0;
    Fa = m*balance(range[ALPHA_RANGE].exact,range[ALPHA_DOT_RANGE].exact);
    Fg = m*g;
    xpos = X_SIZE/2;

    /* angle-Widget */
    angle_tick=0;
    angle_xpos    = ANGLE_DELTA_X;
    angle_oldxpos = 0.0;
    angle_ypos    = Y_SIZE/2 + 0.97*Y_SIZE/2*cos(range[ALPHA_RANGE].exact);
    angle_oldypos = Y_SIZE/2 + 0.97*Y_SIZE/2*cos(range[ALPHA_RANGE].exact);
}

/*************************************************************************/
int main(int argc, char *argv[])
{
    char str[256];
    char str1[256];
    XmString xstr;

    init(argc, argv);

    W_toplevel = XtVaAppInitialize(&app_context,
				   "XPendel7",
				   NULL,0,
				   &argc, argv,
				   NULL,
				   NULL);

    /* Fonts initialisieren */
    fontlist=XmFontListCreate(XLoadQueryFont(XtDisplay(W_toplevel),FONT_NORMAL_NAME),
			      FONT_NORMAL);
    fontlist=XmFontListAdd(fontlist,
			   XLoadQueryFont(XtDisplay(W_toplevel),FONT_BIG_NAME),
			   FONT_BIG);

    W_main = XtVaCreateManagedWidget("main",
				     xmMainWindowWidgetClass,
				     W_toplevel,
				     XmNwidth,X_SIZE,
				     NULL);
      
    {
	/* Menubar */
	W_menubar
	  = XmCreateMenuBar(W_main,"menubar",NULL,0);
	W_file_menu
	  = XmCreatePulldownMenu(W_menubar,"W_file_menu",NULL,0);

	xstr=XmStringCreate("File",FONT_NORMAL);
	W_file_foobar
	  = XtVaCreateManagedWidget("file_foobar",
				    xmCascadeButtonWidgetClass,
				    W_menubar,
				    XmNlabelString,xstr,
				    XmNfontList,fontlist,
				    XmNmnemonic,'F',
				    XmNsubMenuId,W_file_menu,
				    NULL);
	XmStringFree(xstr);

	xstr=XmStringCreate("Reset",FONT_NORMAL);
	W_reset_menuitem
	  = XtVaCreateManagedWidget("reset_menuitem",
				    xmPushButtonGadgetClass,
				    W_file_menu,
				    XmNlabelString,xstr,
				    XmNmnemonic,'R',
				    NULL);
	XmStringFree(xstr);
	XtAddCallback(W_reset_menuitem,XmNactivateCallback,
		      resetCB,NULL);

	xstr=XmStringCreate("Set Defaults",FONT_NORMAL);
	W_setdefaults_menuitem
	  = XtVaCreateManagedWidget("setdefaults_menuitem",
				    xmPushButtonGadgetClass,
				    W_file_menu,
				    XmNlabelString,xstr,
				    XmNmnemonic,'V',
				    NULL);
	XmStringFree(xstr);
	XtAddCallback(W_setdefaults_menuitem,XmNactivateCallback,
		      setdefaultsCB,NULL);

	xstr=XmStringCreate("About",FONT_NORMAL);
	W_about_menuitem
	  = XtVaCreateManagedWidget("about_menuitem",
				    xmPushButtonGadgetClass,
				    W_file_menu,
				    XmNlabelString,xstr,
				    XmNmnemonic,'A',
				    NULL);
	XmStringFree(xstr);
	XtAddCallback(W_about_menuitem,XmNactivateCallback,
		      aboutCB,NULL);

	W_sep_menuitem
	  = XtVaCreateManagedWidget("sep_menuitem",
				    xmSeparatorGadgetClass,
				    W_file_menu,
				    NULL);

	xstr=XmStringCreate("Quit",FONT_NORMAL);
	W_quit_menuitem
	  = XtVaCreateManagedWidget("quit_menuitem",
				    xmPushButtonGadgetClass,
				    W_file_menu,
				    XmNlabelString,xstr,
				    XmNmnemonic,'Q',
				    NULL);
	XmStringFree(xstr);
	XtAddCallback(W_quit_menuitem,XmNactivateCallback,
		      quitCB,NULL);

	XtManageChild(W_menubar);
    }

    W_rc_outer = XtVaCreateManagedWidget("rc_outer",
					 xmRowColumnWidgetClass,
					 W_main,
					 XmNorientation,XmVERTICAL,
					 NULL);
    {
	/* Titel */
	W_title_form
	  = XtVaCreateManagedWidget("title_form",
				    xmFormWidgetClass,
				    W_rc_outer,
				    XmNfractionBase,1,
				    NULL);
	
	xstr=XmStringCreate("Fuzzy-Pendel",FONT_BIG);
	W_title
	  = XtVaCreateManagedWidget("title",
				    xmLabelWidgetClass,
				    W_title_form,
				    XmNlabelString,xstr,
				    XmNfontList,fontlist,
				    XmNalignment,XmALIGNMENT_CENTER,
				    XmNleftAttachment,XmATTACH_POSITION,
				    XmNleftPosition,0,
				    XmNrightAttachment,XmATTACH_POSITION,
				    XmNrightPosition,1,
				    NULL);
	XmStringFree(xstr);
    }
    
    W_sep1
      = XtVaCreateManagedWidget("sep1",
				xmSeparatorWidgetClass,
				W_rc_outer,
				NULL);
    {
	{
	    /* Pendel-Widget mit zwei Pfeilen */
	    W_form_pendel
	      = XtVaCreateManagedWidget("form_pendel",
					xmFormWidgetClass,
					W_rc_outer,
					XmNfractionBase,PENDEL_FRACTION,
					NULL);
	    {
		{
		    /* Left Arrow */
		    W_push_left
		      = XtVaCreateManagedWidget("push_left",
						xmArrowButtonWidgetClass,
						W_form_pendel,
						XmNwidth,Y_SIZE/3,
						XmNarrowDirection,XmARROW_LEFT,
						XmNtopAttachment,XmATTACH_FORM,
						XmNbottomAttachment,XmATTACH_FORM,
						XmNleftAttachment,XmATTACH_POSITION,
						XmNleftPosition,0,
						XmNrightAttachment,XmATTACH_POSITION,
						XmNrightPosition,1,
						NULL);
		    XtAddCallback(W_push_left,XmNactivateCallback,pushCB,0);
		}
		{
		    /* Pendel-core */
		    W_core_pendel
		      = XtVaCreateManagedWidget("pendel_angle",
						coreWidgetClass,
						W_form_pendel,
						XmNheight, Y_SIZE,
						XmNwidth,  X_SIZE-(2*Y_SIZE/3),
						XmNleftAttachment,XmATTACH_POSITION,
						XmNleftPosition,1,
						XmNrightAttachment,XmATTACH_POSITION,
						XmNrightPosition,PENDEL_FRACTION-1,
						NULL);
		}
		{
		    /* Right Arrow */
		    W_push_right
		      = XtVaCreateManagedWidget("push_right",
						xmArrowButtonWidgetClass,
						W_form_pendel,
						XmNwidth,Y_SIZE/3,
						XmNtopAttachment,XmATTACH_FORM,
						XmNbottomAttachment,XmATTACH_FORM,
						XmNarrowDirection,XmARROW_RIGHT, 
						XmNleftAttachment,XmATTACH_POSITION,
						XmNleftPosition,PENDEL_FRACTION-1,
						XmNrightAttachment,XmATTACH_POSITION,
						XmNrightPosition,PENDEL_FRACTION,
						NULL);
		    XtAddCallback(W_push_right,
				  XmNactivateCallback,
				  pushCB,
				  (XtPointer)1);
		}
	    }
	}
	{
	    /* Angle-core-Widget */

	    W_core_angle
	     = XtVaCreateManagedWidget("W_core_angle",
				       coreWidgetClass,
				       W_rc_outer,
				       XmNheight, Y_SIZE,
				       XmNwidth,  X_SIZE,
				       NULL);
	}
	{
	    W_form_ranges = XtVaCreateManagedWidget("form_ranges",
						    xmFormWidgetClass,
						    W_rc_outer,
						    XmNfractionBase,3,
						    NULL);
	    {
		int j;

		for(j=0;j<3;j++){
		    int i;
		    
		    sprintf(str,"%s_frame",range[j].title);
		    range[j].W_frame
		      = XtVaCreateManagedWidget(str,
						xmFrameWidgetClass,
						W_form_ranges,
						XmNleftAttachment,XmATTACH_POSITION,
						XmNleftPosition,j,
						XmNrightAttachment,XmATTACH_POSITION,
						XmNrightPosition,j+1,
						NULL);
		    
		    sprintf(str,"%s_box",range[j].title);
		    range[j].W_box
		      = XtVaCreateManagedWidget(str,
						xmRowColumnWidgetClass,
						range[j].W_frame,
						XmNisAligned,False,
						XmNorientation,XmVERTICAL,
						NULL);

		    sprintf(str,"%s_title",range[j].title);
		    xstr=XmStringCreate(range[j].title,FONT_NORMAL);
		    range[j].W_title
		      = XtVaCreateManagedWidget(str,
						xmLabelWidgetClass,
						range[j].W_box,
						XmNfontList,fontlist,
						XmNlabelString,xstr,
						XmNalignment,XmALIGNMENT_CENTER,
						NULL);
		    XmStringFree(xstr);
		    
		    sprintf(str,"%s_sep1",range[j].title);
		    range[j].W_sep1
		      = XtVaCreateManagedWidget(str,
						xmSeparatorWidgetClass,
						range[j].W_box,
						NULL);

		    for(i=0;i<7;i++){
			sprintf(str,"%s_%s_form",range[j].title,range_name[i]);
			range[j].value[i].W_form
			  = XtVaCreateManagedWidget(str,
						    xmFormWidgetClass,
						    range[j].W_box,
						    NULL);
			
			sprintf(str,"%s_%s_label",range[j].title,range_name[i]);
			sprintf(str1,"%s: ",range_name[i]);
			xstr=XmStringCreate(str1,FONT_NORMAL);
			range[j].value[i].W_label
			  = XtVaCreateManagedWidget(str,
						    xmLabelWidgetClass,
						    range[j].value[i].W_form,
						    XmNfontList,fontlist,
						    XmNlabelString,xstr,
						    XmNalignment,XmALIGNMENT_BEGINNING,
						    XmNleftAttachment,XmATTACH_FORM,
						    NULL);
			XmStringFree(xstr);
			
			sprintf(str,"%s_%s_value",range[j].title,range_name[i]);
			sprintf(str1,"%5.3f",range[j].value[i].value);
			xstr=XmStringCreate(str1,FONT_NORMAL);
			range[j].value[i].W_value
			  = XtVaCreateManagedWidget(str,
						    xmLabelWidgetClass,
						    range[j].value[i].W_form,
						    XmNfontList,fontlist,
						    XmNlabelString,xstr,
						    XmNalignment,XmALIGNMENT_END,
						    XmNleftAttachment,XmATTACH_WIDGET,
						    XmNleftWidget,range[j].value[i].W_label,
						    XmNrightAttachment,XmATTACH_FORM,
						    NULL);
		    }
		    sprintf(str,"%s_sep2",range[j].title);
		    range[j].W_sep1
		      = XtVaCreateManagedWidget(str,
						xmSeparatorWidgetClass,
						range[j].W_box,
						NULL);
		    sprintf(str,"%s_core_values",range[j].title);
		    range[j].W_core_values
		      = XtVaCreateManagedWidget(str,
						coreWidgetClass,
						range[j].W_box,
						XmNheight,Y_SIZE,
						XmNleftAttachment,XmATTACH_FORM,
						XmNrightAttachment,XmATTACH_FORM,
						XmNbottomAttachment,XmATTACH_FORM,
						XmNtopAttachment,XmATTACH_WIDGET,
						XmNtopWidget,range[j].W_sep1,
						NULL);

		}
	    }
	}
	{
	    int i;
	    
	    W_form_exacts = XtVaCreateManagedWidget("form_exacts",
						    xmFormWidgetClass,
						    W_rc_outer,
						    XmNfractionBase,3,
						    NULL);

	    for(i=0;i<3;i++){
		sprintf(str,"%s_W_exact",range[i].title);
		if(i==0){
		    sprintf(str1,"%s = %4.1f°",range[i].title,range[i].exact/PI*180.0);
		}else{
		    sprintf(str1,"%s =%6.3f",range[i].title,range[i].exact);
		}
		xstr=XmStringCreate(str1,FONT_NORMAL);
		range[i].W_exact = XtVaCreateManagedWidget(str,
							   xmLabelWidgetClass,
							   W_form_exacts,
							   XmNfontList,fontlist,
							   XmNlabelString,xstr,
							   XmNleftAttachment,XmATTACH_POSITION,
							   XmNleftPosition,i,
							   XmNrightAttachment,XmATTACH_POSITION,
							   XmNrightPosition,i+1,
							   XmNalignment,XmALIGNMENT_BEGINNING,
							   NULL);
		XmStringFree(xstr);
	    }
	}
	
	W_sep2 = XtVaCreateManagedWidget("sep2",
					 xmSeparatorWidgetClass,
					 W_rc_outer,
					 NULL);
	W_form_bottom = XtVaCreateManagedWidget("form_bottom",
						xmFormWidgetClass,
						W_rc_outer,
						XmNfractionBase,10,
						NULL);
	{
	    xstr=XmStringCreate("Start",FONT_NORMAL);
	    W_startstop = XtVaCreateManagedWidget("startstop",
						  xmPushButtonWidgetClass,
						  W_form_bottom,
						  XmNfontList,fontlist,
						  XmNlabelString,xstr,
						  XmNleftAttachment,XmATTACH_POSITION,
						  XmNleftPosition,1,
						  XmNrightAttachment,XmATTACH_POSITION,
						  XmNrightPosition,3,
						  NULL);
	    XtAddCallback(W_startstop,
			  XmNactivateCallback,
			  startstopCB,
			  (XtPointer)1);
	    XmStringFree(xstr);

	    xstr=XmStringCreate("Step",FONT_NORMAL);
	    W_step = XtVaCreateManagedWidget("step",
					     xmPushButtonWidgetClass,
					     W_form_bottom,
					     XmNfontList,fontlist,
					     XmNlabelString,xstr,
					     XmNleftAttachment,XmATTACH_POSITION,
					     XmNleftPosition,4,
					     XmNrightAttachment,XmATTACH_POSITION,
					     XmNrightPosition,6,
					     NULL);
	    XtAddCallback(W_step,
			  XmNactivateCallback,
			  stepCB,
			  (XtPointer)1);
	    XtSetSensitive(W_step,True);
	    XmStringFree(xstr);

	    xstr=XmStringCreate("Quit",FONT_NORMAL);
	    W_quit = XtVaCreateManagedWidget("quit",
					     xmPushButtonWidgetClass,
					     W_form_bottom,
					     XmNfontList,fontlist,
					     XmNlabelString,xstr,
					     XmNleftAttachment,XmATTACH_POSITION,
					     XmNleftPosition,7,
					     XmNrightAttachment,XmATTACH_POSITION,
					     XmNrightPosition,9,
					     NULL);
	    XtAddCallback(W_quit,
			  XmNactivateCallback,
			  quitCB,
			  (XtPointer)1);
	    XmStringFree(xstr);
	}
    }

    XtRealizeWidget(W_toplevel);

    {
	int screen;
	int i;
	Display *display;
	
	/* core_angle-init */
	display = XtDisplay(W_rc_outer);
	screen  = DefaultScreen(display);

	black = BlackPixel(display,screen);
	white = WhitePixel(display,screen);

	gc_core_angle  = XCreateGC(display,XtWindow(W_core_angle),0,NULL);
	XSetForeground(display,gc_core_angle,black);
	XSetBackground(display,gc_core_angle,white);

	gc_core_pendel  = XCreateGC(display,XtWindow(W_core_pendel),0,NULL);
	XSetForeground(display,gc_core_pendel,black);
	XSetBackground(display,gc_core_pendel,white);

	cmap=DefaultColormap(display,screen);
	col_red.red   = 255<<8;
	col_red.green =   0<<8;
	col_red.blue  =   0<<8;
	XAllocColor(display, cmap, &col_red);
	
	col_yellow.red   = 255<<8;
	col_yellow.green = 255<<8;
	col_yellow.blue  =   0<<8;
	XAllocColor(display, cmap, &col_yellow);

	for(i=0;i<3;i++){
	    range[i].gc_core_values
	      = XCreateGC(display,XtWindow(range[i].W_core_values),0,NULL);
	    XSetForeground(display,range[i].gc_core_values,black);
	    XSetBackground(display,range[i].gc_core_values,white);
	}
    }
    XFlush(XtDisplay(W_toplevel));

    {
	int i;
	for(i=0;i<10;i++)
	  update_widgets(1);
	resetCB(0,0,0);
    }

    XtAppMainLoop(app_context);
    /*NOTREACHED*/
    return 0;
}
