
#include "mview_slice.h"

#include "gx11/visual_context.h"
#include "mview_main.h"
#include "mview_spectrum.h"
#include "mview_cursor.h"
#include "mview_display.h"
#include "mview_view.h"
#include "mview_widgets.h"
#include "mview_misc.h"
#include "mview_macros.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#include <Xm/MwmUtil.h>
#include <Xm/Text.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/Form.h>
#include <Xm/DrawingA.h>
#include <Xm/XmStrDefs.h>

extern int cursor_mode, ticwidth;
extern int xoffset, yoffset;
static Widget sliceshell = 0;
static char dumstr[80];

int veloleft = 1;

static char slice_translations[] = "<Motion>: slice_input( )\n\
                    <EnterNotify>: slice_input( )\n\
                    <LeaveNotify>: slice_input( )\n\
                    <Btn1Down>: slice_input( )\n\
                    <Btn2Down>: slice_input( )\n\
                    <Btn1Up>: slice_input( )\n\
                    <Btn2Up>: slice_input( )\n\
                    <Btn3Down>: slice_input( )\n";

static char spectrum_slice_translations[] = "<Motion>: spectrum_slice_input( )\n\
                    <EnterNotify>: spectrum_slice_input( )\n\
                    <LeaveNotify>: spectrum_slice_input( )\n\
                    <Btn1Down>: spectrum_slice_input( )\n\
                    <Btn1Up>: spectrum_slice_input( )\n\
                    <Btn2Down>: spectrum_slice_input( )\n\
                    <Btn2Up>: spectrum_slice_input( )\n\
                    <Btn3Down>: spectrum_slice_input( )\n";

static char coupe_translations[] = "<Btn1Down>: coupe_input( )\n\
                    <Btn1Up>: coupe_input( )\n\
                    <Motion>: coupe_input( )\n";


static int xr, yr;              /* origin of current slice in mosaic */
static int xz, yz;              /* origin of current slice in zoomed subset */

static int prev_xc, prev_yc;    /* previous current position in mosaic */
static int prev_xzc, prev_yzc;  /* previous current position in zoom */

static int edit = 0, enf = 0, mem = 0;  /* flags */

int Np;                         /* Number of points along the slice */
float *Buffer = NULL;           /* Buffer for slice values  */

static float *Lgu = NULL, *Mgu = NULL;  /* Arrays for slice grid coordinates */
static float minintspec_along, maxintspec_along, intspec_along[512];
static XPoint isp_a[512];

static XImage *simage;          /* image for slice */
static char *pixslice;          /* Array of pixels for slice */

extern void change_pixmap( int z);
extern void change_tic( int z);

void redraws_slice( )
{
    int z;

    if (edit) {
        for (z = 0; z < Nsubs; z++)
            LINE(radec, POSX(xr, z), POSY(yr, z), POSX(prev_xc, z), POSY(prev_yc, z));
    }
}



static int xs[2], ys[2];        /* slice extremities */
static int zxs[2], zys[2];      /* slice extremities in spectrum window */


void redraws_slice_in_subset( )
{
    if (edit) {
        if (subpixmap[0] == 0)
            LINE(subset, xr + xoffset, yr + yoffset, prev_xc + xoffset, prev_yc + yoffset);
        else
            LINE(subset, zxs[0], zys[0], zxs[1], zys[1]);
    }
}

void redraws_slice_in_integmean( )
{
    if (edit)
        LINE(integmean, zxs[0], zys[0], zxs[1], zys[1]);
}

void dismiss_slice( Widget w, int *code, XmDrawingAreaCallbackStruct * cbs)
{
    reset_slice( );
    XtUnmapWidget( sliceshell);
    spectrum( );
}

void slice( )
{

    if (sliceshell == 0) {
        sliceshell = XtVaAppCreateShell( "Slice/Integrated profile (in intensity)",
                                        "sliceshell",
                                        topLevelShellWidgetClass,
                                        XtDisplay( toplevel),
                                        XmNmappedWhenManaged, False,
                                        XmNmwmDecorations, MWM_DECOR_TITLE | MWM_DECOR_BORDER | MWM_DECOR_MINIMIZE, NULL);

        slice_w = XtVaCreateManagedWidget( "slice_w", xmFormWidgetClass, sliceshell, NULL);
        sliceticks = XtVaCreateManagedWidget( "sliceticks",
                                             xmDrawingAreaWidgetClass,
                                             slice_w, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, NULL);
        create( sliceticks, k_sliceticks, NULL);
        XtAddCallback( sliceticks, XmNexposeCallback, (XtCallbackProc) expose, (XtPointer) k_sliceticks);

        slicelab = XtVaCreateManagedWidget( "slicelab", xmTextWidgetClass, slice_w, XmNbackground, blackpix, XmNforeground, whitepix,

/* 				     XmNfontList, font( "6x10"), */
                                           XmNeditable, False,
                                           XmNtraversalOn, False,
                                           XmNcursorPositionVisible, False,
                                           XmNtopAttachment, XmATTACH_WIDGET,
                                           XmNtopWidget, sliceticks, XmNleftAttachment, XmATTACH_FORM, NULL);
        create( slicelab, k_slicelab, NULL);

        ldrawaxes = XtVaCreateManagedWidget( "ldrawaxes",
                                            xmDrawingAreaWidgetClass,
                                            slice_w,
                                            XmNtopAttachment, XmATTACH_FORM,
                                            XmNleftAttachment, XmATTACH_WIDGET,
                                            XmNleftWidget, sliceticks, XmNbackground, blackpix, XmNwidth, 30, NULL);
        create( ldrawaxes, k_ldrawaxes, NULL);
        XtAddCallback( ldrawaxes, XmNexposeCallback, (XtCallbackProc) expose, (XtPointer) k_ldrawaxes);

        coupe = XtVaCreateManagedWidget( "coupe",
                                        xmDrawingAreaWidgetClass,
                                        slice_w,
                                        XmNtopAttachment, XmATTACH_FORM,
                                        XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ldrawaxes, NULL);
        create( coupe, k_coupe, NULL);
        XtAddCallback( coupe, XmNexposeCallback, (XtCallbackProc) expose, (XtPointer) k_coupe);

        rdrawaxes = XtVaCreateManagedWidget( "rdrawaxes",
                                            xmDrawingAreaWidgetClass,
                                            slice_w,
                                            XmNtopAttachment, XmATTACH_FORM,
                                            XmNleftAttachment, XmATTACH_WIDGET,
                                            XmNleftWidget, coupe, XmNbackground, blackpix, XmNwidth, 30, NULL);
        create( rdrawaxes, k_rdrawaxes, NULL);
        XtAddCallback( rdrawaxes, XmNexposeCallback, (XtCallbackProc) expose, (XtPointer) k_rdrawaxes);

        coupe_integ = XtVaCreateManagedWidget( "coupe_integ",
                                              xmDrawingAreaWidgetClass,
                                              slice_w,
                                              XmNtopAttachment, XmATTACH_FORM,
                                              XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, rdrawaxes, NULL);
        create( coupe_integ, k_coupe_integ, NULL);
        XtAddCallback( coupe_integ, XmNexposeCallback, (XtCallbackProc) expose, (XtPointer) k_coupe_integ);


        drawaxes = XtVaCreateManagedWidget( "drawaxes",
                                           xmDrawingAreaWidgetClass,
                                           slice_w,
                                           XmNtopAttachment, XmATTACH_WIDGET,
                                           XmNtopWidget, coupe_integ,
                                           XmNleftAttachment, XmATTACH_WIDGET,
                                           XmNleftWidget, ldrawaxes, XmNheight, 30, XmNbackground, blackpix, NULL);
        create( drawaxes, k_drawaxes, NULL);
        XtAddCallback( drawaxes, XmNexposeCallback, (XtCallbackProc) expose, (XtPointer) k_drawaxes);

        axeinteg = XtVaCreateManagedWidget( "axeinteg",
                                           xmDrawingAreaWidgetClass,
                                           slice_w,
                                           XmNtopAttachment, XmATTACH_WIDGET,
                                           XmNtopWidget, coupe_integ,
                                           XmNleftAttachment, XmATTACH_WIDGET,
                                           XmNleftWidget, rdrawaxes, XmNbackground, blackpix, XmNheight, 30, NULL);

        slice_dismiss = XtVaCreateManagedWidget( "Dismiss", xmPushButtonGadgetClass, slice_w,

/* 					   XmNfontList, font( "8x13"), */
                                                XmNtraversalOn, False,
                                                XmNtopAttachment, XmATTACH_WIDGET,
                                                XmNtopWidget, drawaxes,
                                                XmNrightAttachment, XmATTACH_FORM,
                                                XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL);
        XtAddCallback( slice_dismiss, XmNactivateCallback, (XtCallbackProc) dismiss_slice, NULL);

        XtRealizeWidget( sliceshell);


        pixslice = (char *)malloc( slicewidth * slice_zoomx * Nsubs * slice_zoomy * sizeof( char));
        simage = XCreateImage( display, g_vc.visual, g_vc.depth, ZPixmap, 0, pixslice, slice_zoomx * Np, slice_zoomy * Nsubs, 8, 0);

        /* Allocate memory for slice floatimage and grid coordinates */
        if (Buffer != NULL) {
            free( Buffer);
            free( Lgu);
            free( Mgu);
        }
        Buffer = (float *)malloc( slicewidth * Nsubs * sizeof( float));
        Lgu = (float *)malloc( slicewidth * sizeof( float));
        Mgu = (float *)malloc( slicewidth * sizeof( float));

        set_colormap( sliceshell);
    }

    else {
        XMapRaised( display, XtWindow( sliceshell));

        if (cursor_mode == SLICE)
            return;

        if (mem) {
            edit = 1;
            redraws_slice( );
            if (Nsubs >= 2) {
                redraws_slice_in_subset( );
                redraws_slice_in_integmean( );
            }
        }
        XtVaSetValues( radec, XmNtranslations, XtParseTranslationTable( slice_translations), NULL);

        XtVaSetValues( coupe, XmNtranslations, XtParseTranslationTable( coupe_translations), NULL);
        if (Nsubs >= 2) {
            XtVaSetValues( subset, XmNtranslations, XtParseTranslationTable( spectrum_slice_translations), NULL);
            XtVaSetValues( integmean, XmNtranslations, XtParseTranslationTable( spectrum_slice_translations), NULL);
        }

        cursor_mode = SLICE;
    }

}


void draw_integspec_along( )
{
    int i;
    int offset = (slice_zoomx * slicewidth) / 2 - (slice_zoomx * Np) / 2;

    XSetForeground( display, gc, g_vc.black_pixel);
    XFillRectangle( display, ipixmap, gc, 0, 0, slicewidth * slice_zoomx, slice_zoomy * Nsubs);
    XSetForeground( display, gc, g_vc.white_pixel);

    for (i = 0; i < Np - 1; i++) {
        XDrawLine( display, ipixmap, gc,
                  offset + slice_zoomx * i, isp_a[i].y, offset + slice_zoomx * i + slice_zoomx - 1, isp_a[i].y);
        XDrawLine( display, ipixmap, gc,
                  offset + slice_zoomx * i + slice_zoomx - 1, isp_a[i].y,
                  offset + slice_zoomx * i + slice_zoomx - 1, isp_a[i + 1].y);
    }

    XDrawLine( display, ipixmap, gc,
              offset + slice_zoomx * (Np - 1), isp_a[Np - 1].y, offset + slice_zoomx * (Np - 1) + slice_zoomx - 1, isp_a[Np - 1].y);


    XDrawLine( display, ipixmap, gc,
              0,
              (int)((float)(slice_zoomy * Nsubs - 1) * (1. - (-minintspec_along) /
                                                        (maxintspec_along - minintspec_along))),
              slice_zoomx * slicewidth,
              (int)((float)(slice_zoomy * Nsubs - 1) * (1. - (-minintspec_along) / (maxintspec_along - minintspec_along))));

    XCopyArea( display, ipixmap, XtWindow( coupe_integ), gc, 0, 0, slicewidth * slice_zoomx, slice_zoomy * Nsubs, 0, 0);

}

extern int stick1, stick2;
void new_profile( )
{
    int z, p;

    for (p = 0; p < Np; p++) {
        intspec_along[p] = 0;
        for (z = stick1; z <= stick2; z++)
            intspec_along[p] = intspec_along[p] + Buffer[z * Np + p];
    }
    minintspec_along = min( 0, intspec_along[0]);
    maxintspec_along = intspec_along[0];
    for (p = 1; p < Np; p++) {
        if (intspec_along[p] < minintspec_along)
            minintspec_along = intspec_along[p];
        if (intspec_along[p] > maxintspec_along)
            maxintspec_along = intspec_along[p];
    }


    if (minintspec_along != maxintspec_along) {
        for (p = 0; p < Np; p++) {
            isp_a[p].y = (slice_zoomy * Nsubs) *
             (1 - (intspec_along[p] - minintspec_along) / (maxintspec_along - minintspec_along));
        }

        draw_integspec_along( );

    }

}


#if 0
void dynamic_slice( double x0, double y0, double x1, double y1)
{
    register float dl, dm;
    register double dx, dy;
    int i, j, p, z;

    if (x0 == x1) {
        dx = 0.;
        dy = (double)incr;
        Np = (fabs( y1 - y0) + 1.) / incr;
        if (Np > slicewidth)
            Np = slicewidth;
    } else if (y0 == y1) {
        dx = (double)incr;
        dy = 0.;
        Np = (fabs( x1 - x0) + 1.) / incr;
        if (Np > slicewidth)
            Np = slicewidth;
    } else {
        dl = fabs( x1 - x0);
        dm = fabs( y1 - y0);
        Np = (int)sqrt( (double)(dl + 1.) / incr * (dl + 1.) / incr + (dm + 1.) / incr * (dm + 1.) / incr);
        if (Np > slicewidth)
            Np = slicewidth;
        if (Np == 0)
            return;
        dx = (double)dl / Np;
        dy = (double)dm / Np;
    }


    if (x1 < x0)
        dx = -dx;

    if (y1 < y0)
        dy = -dy;

    Lgu[0] = (float)x0;
    Mgu[0] = (float)y0;

    for (i = 1; i < Np; i++) {
        Lgu[i] = Lgu[i - 1] + (float)dx;
        Mgu[i] = Mgu[i - 1] + (float)dy;
        if ((Lgu[i] < 0) || (Lgu[i] >= npix[0]) || (Mgu[i] < 0) || (Mgu[i] >= npix[1])) {

            sprintf( dumstr, "error Lgu = %f Mgu = %f\n", Lgu[i], Mgu[i]);
            printf( dumstr);
            if (Lgu[i] < 0.)
                Lgu[i] = 0.;
            if (Mgu[i] < 0.)
                Mgu[i] = 0.;
            if (Lgu[i] >= (float)npix[0])
                Lgu[i] = (float)npix[0] - 1.;
            if (Mgu[i] >= (float)npix[1])
                Mgu[i] = (float)npix[1] - 1.;
        }

    }

/*
  Lgu[Np-1] = (float) x1;
  Mgu[Np-1] = (float) y1; 
*/
    for (p = 0; p < Np; p++)
        intspec_along[p] = 0.;

    for (z = 0; z < Nsubs; z++) {
        for (p = 0; p < Np; p++) {
            i = (int)Lgu[p];
            j = (int)Mgu[p];


            dx = Lgu[p] - (float)i;
            dy = Mgu[p] - (float)j;


            if ((z * Np + p) >= slicewidth * Nsubs) {
                sprintf( dumstr, "error slicewidth = %d %s %d\n", slicewidth * Nsubs, "d = ", z * Np + p);
                printf( dumstr);
            }

            if ((i + 1 < npix[0]) && (j + 1 < npix[1]))
                Buffer[z * Np + p] = dx * dy * (*(F_ADDR((i + 1), (npix[1] - 1 - (j + 1)), z)))
                 + (1.0 - dx) * dy * (*(F_ADDR(i, (npix[1] - 1 - (j + 1)), z)))
                 + (1.0 - dx) * (1.0 - dy) * (*(F_ADDR(i, (npix[1] - 1 - j), z)))
                 + dx * (1.0 - dy) * (*(F_ADDR((i + 1), (npix[1] - 1 - j), z)));

            else if (i + 1 < npix[0])
                Buffer[z * Np + p] = dx * dy * (*(F_ADDR((i + 1), (npix[1] - 1 - j), z)))
                 + (1.0 - dx) * dy * (*(F_ADDR(i, (npix[1] - 1 - j), z)))
                 + (1.0 - dx) * (1.0 - dy) * (*(F_ADDR(i, (npix[1] - 1 - j), z)))
                 + dx * (1.0 - dy) * (*(F_ADDR((i + 1), (npix[1] - 1 - j), z)));
            else if (j + 1 < npix[1])
                Buffer[z * Np + p] = dx * dy * (*(F_ADDR(i, (npix[1] - 1 - (j + 1)), z)))
                 + (1.0 - dx) * dy * (*(F_ADDR(i, (npix[1] - 1 - (j + 1)), z)))
                 + (1.0 - dx) * (1.0 - dy) * (*(F_ADDR(i, (npix[1] - 1 - j), z)))
                 + dx * (1.0 - dy) * (*(F_ADDR(i, (npix[1] - 1 - j), z)));
            else
                Buffer[z * Np + p] = (*(F_ADDR(i, (npix[1] - 1 - j), z)));

            if ((z >= stick1) && (z <= stick2))
                intspec_along[p] = intspec_along[p] + Buffer[z * Np + p];

        }
    }

  /** Draw integ spec along slice **/

    minintspec_along = min( 0, intspec_along[0]);
    maxintspec_along = intspec_along[0];
    for (p = 1; p < Np; p++) {
        if (intspec_along[p] < minintspec_along)
            minintspec_along = intspec_along[p];
        if (intspec_along[p] > maxintspec_along)
            maxintspec_along = intspec_along[p];
    }


    if (minintspec_along != maxintspec_along) {
        for (p = 0; p < Np; p++) {
            isp_a[p].y = (slice_zoomy * Nsubs) *
             (1 - (intspec_along[p] - minintspec_along) / (maxintspec_along - minintspec_along));
        }

        draw_integspec_along( );

    }

    XSetForeground( display, gc, g_vc.black_pixel);

    XFillRectangle( display, spixmap, gc, 0, 0, slice_zoomx * slicewidth, slice_zoomy * Nsubs);

    AffImage( Buffer, spixmap, slice_zoomx * Np, slice_zoomy * Nsubs,
             1, Np, 1, Nsubs,
             slice_zoomx, slice_zoomy, displayclip[0], displayclip[1], 1,
             0, 0, (slice_zoomx * slicewidth) / 2 - (slice_zoomx * Np) / 2, 0, slice_zoomx * Np, slice_zoomy * Nsubs);

    XCopyArea( display, spixmap, XtWindow( coupe), gc, 0, 0, slice_zoomx * slicewidth, slice_zoomy * Nsubs, 0, 0);
}

#endif
void dynamic_slice_with_blanks( double x0, double y0, double x1, double y1)
{
    register float dl, dm;
    register double dx, dy;
    int i, j, p, z;
    float coeff[4];

    if (x0 == x1) {
        dx = 0.;
        dy = (double)incr;
        Np = (fabs( y1 - y0) + 1.) / incr;
    } else if (y0 == y1) {
        dx = (double)incr;
        dy = 0.;
        Np = (fabs( x1 - x0) + 1.) / incr;
    } else {
        dl = fabs( x1 - x0);
        dm = fabs( y1 - y0);
        Np = sqrt( (dl + 1.) * (dl + 1.) / (incr * incr) + (dm + 1) * (dm + 1) / (incr * incr));

        if (Np > slicewidth)
            Np = slicewidth;
        if (Np == 0)
            return;

        dx = (double)dl / Np;
        dy = (double)dm / Np;
    }


    if (x1 < x0)
        dx = -dx;

    if (y1 < y0)
        dy = -dy;

    Lgu[0] = (float)x0;
    Mgu[0] = (float)y0;

    for (i = 1; i < Np; i++) {
        Lgu[i] = Lgu[i - 1] + (float)dx;
        Mgu[i] = Mgu[i - 1] + (float)dy;
    }

    for (p = 0; p < Np; p++)
        intspec_along[p] = 0.;

    for (z = 0; z < Nsubs; z++) {
        for (p = 0; p < Np; p++) {
            coeff[0] = 1.;
            coeff[1] = 1.;
            coeff[2] = 1.;
            coeff[3] = 1.;
            i = (int)Lgu[p];
            j = (int)Mgu[p];

            dx = Lgu[p] - (float)i;
            dy = Mgu[p] - (float)j;

            if ((i < 0) || (j < 0) || (i >= npix[0] - 1) || (j >= npix[1] - 1))
                /* outside image */
                Buffer[z * Np + p] = Blank;
            else {
                if (*(F_ADDR(i, (npix[1] - 1 - j), z)) == Blank) {
                    if ((dx <= 0.5) && (dy <= 0.5)) {
                        Buffer[z * Np + p] = Blank;
                        continue;
                    } else
                        coeff[0] = 0.;
                }
                if (*(F_ADDR((i + 1), (npix[1] - 1 - j), z)) == Blank) {
                    if ((dx > 0.5) && (dy <= 0.5)) {
                        Buffer[z * Np + p] = Blank;
                        continue;
                    } else
                        coeff[1] = 0.;
                }
                if (*(F_ADDR(i, (npix[1] - 1 - (j + 1)), z)) == Blank) {
                    if ((dx <= 0.5) && (dy > 0.5)) {
                        Buffer[z * Np + p] = Blank;
                        continue;
                    } else
                        coeff[2] = 0.;
                }
                if (*(F_ADDR((i + 1), (npix[1] - 1 - (j + 1)), z)) == Blank) {
                    if ((dx > 0.5) && (dy > 0.5)) {
                        Buffer[z * Np + p] = Blank;
                        continue;
                    } else
                        coeff[3] = 0.;
                }

                Buffer[z * Np + p] = (1.0 - dx) * (1.0 - dy) * coeff[0] * (*(F_ADDR(i, (npix[1] - 1 - j), z)))
                 + dx * (1.0 - dy) * coeff[1] * (*(F_ADDR((i + 1), (npix[1] - 1 - j), z)))
                 + (1.0 - dx) * dy * coeff[2] * (*(F_ADDR(i, (npix[1] - 1 - (j + 1)), z)))
                 + dx * dy * coeff[3] * (*(F_ADDR((i + 1), (npix[1] - 1 - (j + 1)), z)));

                if ((z >= stick1) && (z <= stick2))
                    intspec_along[p] = intspec_along[p] + Buffer[z * Np + p];
            }
        }
    }

  /** Draw integ spec along slice **/

    minintspec_along = min( 0, intspec_along[0]);
    maxintspec_along = intspec_along[0];
    for (p = 1; p < Np; p++) {
        if (intspec_along[p] < minintspec_along)
            minintspec_along = intspec_along[p];
        if (intspec_along[p] > maxintspec_along)
            maxintspec_along = intspec_along[p];
    }


    if (minintspec_along != maxintspec_along) {
        for (p = 0; p < Np; p++) {
            isp_a[p].y = (slice_zoomy * Nsubs) *
             (1 - (intspec_along[p] - minintspec_along) / (maxintspec_along - minintspec_along));
        }

        draw_integspec_along( );

    }

    XSetForeground( display, gc, g_vc.black_pixel);

    XFillRectangle( display, spixmap, gc, 0, 0, slice_zoomx * slicewidth, slice_zoomy * Nsubs);

    AffImage( Buffer, spixmap, slice_zoomx * Np, slice_zoomy * Nsubs,
             1, Np, 1, Nsubs,
             slice_zoomx, slice_zoomy, displayclip[0], displayclip[1], 1,
             0, 0, (slice_zoomx * slicewidth) / 2 - (slice_zoomx * Np) / 2, 0, slice_zoomx * Np, slice_zoomy * Nsubs);

    XCopyArea( display, spixmap, XtWindow( coupe), gc, 0, 0, slice_zoomx * slicewidth, slice_zoomy * Nsubs, 0, 0);
}

void dynamic_slice( double x0, double y0, double x1, double y1)
{
    register float dl, dm;
    register double dx, dy;
    int i, j, p, z;

    if (x0 == x1) {
        dx = 0.;
        dy = (double)incr;
        Np = (fabs( y1 - y0) + 1.) / incr;
    } else if (y0 == y1) {
        dx = (double)incr;
        dy = 0.;
        Np = (fabs( x1 - x0) + 1.) / incr;
    } else {
        dl = fabs( x1 - x0);
        dm = fabs( y1 - y0);
        Np = sqrt( (dl + 1.) * (dl + 1.) / (incr * incr) + (dm + 1) * (dm + 1) / (incr * incr));

        if (Np > slicewidth)
            Np = slicewidth;
        if (Np == 0)
            return;

        dx = (double)dl / Np;
        dy = (double)dm / Np;
    }

    if (x1 < x0)
        dx = -dx;

    if (y1 < y0)
        dy = -dy;

    Lgu[0] = (float)x0;
    Mgu[0] = (float)y0;

    for (i = 1; i < Np; i++) {
        Lgu[i] = Lgu[i - 1] + (float)dx;
        Mgu[i] = Mgu[i - 1] + (float)dy;
    }

    for (p = 0; p < Np; p++)
        intspec_along[p] = 0.;

    for (z = 0; z < Nsubs; z++) {
        for (p = 0; p < Np; p++) {
            i = (int)Lgu[p];
            j = (int)Mgu[p];

            dx = Lgu[p] - (float)i;
            dy = Mgu[p] - (float)j;

            if ((i < 0) || (j < 0) || (i >= npix[0] - 1) || (j >= npix[1] - 1))
                Buffer[z * Np + p] = Blank;
            else {
                Buffer[z * Np + p] = dx * dy * (*(F_ADDR((i + 1), (npix[1] - 1 - (j + 1)), z)))
                 + (1.0 - dx) * dy * (*(F_ADDR(i, (npix[1] - 1 - (j + 1)), z)))
                 + (1.0 - dx) * (1.0 - dy) * (*(F_ADDR(i, (npix[1] - 1 - j), z)))
                 + dx * (1.0 - dy) * (*(F_ADDR((i + 1), (npix[1] - 1 - j), z)));

                if ((z >= stick1) && (z <= stick2))
                    intspec_along[p] = intspec_along[p] + Buffer[z * Np + p];
            }
        }
    }

  /** Draw integ spec along slice **/

    minintspec_along = min( 0, intspec_along[0]);
    maxintspec_along = intspec_along[0];
    for (p = 1; p < Np; p++) {
        if (intspec_along[p] < minintspec_along)
            minintspec_along = intspec_along[p];
        if (intspec_along[p] > maxintspec_along)
            maxintspec_along = intspec_along[p];
    }


    if (minintspec_along != maxintspec_along) {
        for (p = 0; p < Np; p++) {
            isp_a[p].y = (slice_zoomy * Nsubs) *
             (1 - (intspec_along[p] - minintspec_along) / (maxintspec_along - minintspec_along));
        }

        draw_integspec_along( );

    }

    XSetForeground( display, gc, g_vc.black_pixel);

    XFillRectangle( display, spixmap, gc, 0, 0, slice_zoomx * slicewidth, slice_zoomy * Nsubs);

    AffImage( Buffer, spixmap, slice_zoomx * Np, slice_zoomy * Nsubs,
             1, Np, 1, Nsubs,
             slice_zoomx, slice_zoomy, displayclip[0], displayclip[1], 1,
             0, 0, (slice_zoomx * slicewidth) / 2 - (slice_zoomx * Np) / 2, 0, slice_zoomx * Np, slice_zoomy * Nsubs);

    XCopyArea( display, spixmap, XtWindow( coupe), gc, 0, 0, slice_zoomx * slicewidth, slice_zoomy * Nsubs, 0, 0);
}


extern XImage *hugeimage;
extern char *lotofpixels;
extern Widget zoomshell, zoom_w;
extern Dimension zoom_width, zoom_height;

void draw_angle( )
{
    if (prev_xc == yr)
        return;
    XSetForeground( display, gc, g_vc.black_pixel);
    XFillRectangle( display, XtWindow( drawaxes), gc, 50, 10, slicewidth * slice_zoomx - 100, 20);
    XSetForeground( display, gc, g_vc.white_pixel);
    if (prev_yc != yr)
        sprintf( dumstr, "Angle from North %4.2f", (180. / 3.14159) * atan( (double)(prev_xc - xr) / (prev_yc - yr)));
    else
        sprintf( dumstr, "Angle from North %4.2f", 90.0);

    XDrawString( display, XtWindow( drawaxes), gc, 50, 20, dumstr, strlen( dumstr));
    XFlush( display);


}


void slice_input( Widget w, XEvent * event)
{
    int x, y, z, zc, d, D, n, N;
    int xc, yc;                 /* current position */
    static int zr, prev_zr = -1;
    static int in = 1;
    static int prev_trx, prev_try, enf2 = 0;
    static int axeperm = 1;

    switch (event->type) {
    case EnterNotify:
        in = 1;
        break;
    case ButtonPress:
        switch (event->xbutton.button) {
        case Button1:
            x = event->xbutton.x;
            y = event->xbutton.y;

            zc = GETZ(x, y);           /* calcul provisoire de z */
            if (zc >= Nsubs)
                return;

            /* current position */
            xr = GETX(x);
            yr = GETY(y);
            zr = zc;

            if (prev_zr != -1)
                WHITEAREA(prev_zr);
            REDAREA(zr);

            enf = 1;
            kill_movie( );

            if (!edit) {
                /* initialize previous position */
                prev_xc = xr;
                prev_yc = yr;
            }

            else {
                /* find new origin */
                D = 1E+05;
                for (n = 0; n < 2; n++) {
                    d = sqrt( (float)((ys[n] - yr) * (ys[n] - yr)
                                     + (xs[n] - xr) * (xs[n] - xr)));
                    if (d < D) {
                        D = d;
                        N = n;
                    }
                }

                switch (N) {
                case 0:
                    xr = xs[1];
                    yr = ys[1];
                    veloleft = (veloleft + 1) % 2;
                    axeperm = 1;
                    break;
                case 1:
                    xr = xs[0];
                    yr = ys[0];
                    break;
                }

                /* re-initialize previous position */
                prev_xc = xs[N];
                prev_yc = ys[N];
            }

            if (zr != prev_zr) {
                prev_zr = zr;
            }

            break;
        case Button2:
            prev_trx = event->xbutton.x;
            prev_try = event->xbutton.y;

            zc = GETZ(prev_trx, prev_try);      /* calcul provisoire de z */
            if (zc >= Nsubs)
                return;

            zr = zc;

            if (prev_zr != -1)
                WHITEAREA(prev_zr);
            REDAREA(zr);

            enf2 = 1;
            kill_movie( );

            if (zr != prev_zr) {
                prev_zr = zr;
            }
            axeperm = 1;
            break;
        }
        break;

    case MotionNotify:
        x = event->xmotion.x;
        y = event->xmotion.y;

        zc = GETZ(x, y);

        if ((!enf && !enf2) || (!in) || (zc >= Nsubs) || (zc != zr))
            return;

        if (axeperm) {
            axeperm = 0;

            draw_axes( );
        }

        /* current position */
        xc = GETX(x);
        yc = GETY(y);

        if (enf2) {

            if ((xr + x - prev_trx < 0) || (yr + y - prev_try < 0)
                || (prev_xc + x - prev_trx < 0)
                || (prev_yc + y - prev_try < 0))
                return;
            if ((xr + x - prev_trx >= sizex) || (yr + y - prev_try >= sizey)
                || (prev_xc + x - prev_trx >= sizex)
                || (prev_yc + y - prev_try >= sizey))
                return;



            LINE(radec, POSX(xr, zr), POSY(yr, zr), POSX(prev_xc, zr), POSY(prev_yc, zr));


            xr = xr + x - prev_trx;
            yr = yr + y - prev_try;
            xc = prev_xc + x - prev_trx;
            yc = prev_yc + y - prev_try;

            prev_trx = x;
            prev_try = y;

            LINE(radec, POSX(xr, zr), POSY(yr, zr), POSX(xc, zr), POSY(yc, zr));


            if (Tolerance < 0)
                dynamic_slice( ((double)(incr * xr) / zoom), ((double)(incr * yr) / zoom),
                              ((double)(incr * xc) / zoom), ((double)(incr * yc) / zoom));
            else
                dynamic_slice_with_blanks( ((double)(incr * xr) / zoom),
                                          ((double)(incr * yr) / zoom), ((double)(incr * xc) / zoom), ((double)(incr * yc) / zoom));

        } else {


            LINE(radec, POSX(xr, zr), POSY(yr, zr), POSX(prev_xc, zr), POSY(prev_yc, zr));
            LINE(radec, POSX(xr, zr), POSY(yr, zr), POSX(xc, zr), POSY(yc, zr));


            if ((xc != xr) || (yc != yr)) {
                if (Tolerance < 0)
                    dynamic_slice( ((double)(incr * xr) / zoom), ((double)(incr * yr) / zoom),
                                  ((double)(incr * xc) / zoom), ((double)(incr * yc) / zoom));
                else
                    dynamic_slice_with_blanks( ((double)(incr * xr) / zoom),
                                              ((double)(incr * yr) / zoom),
                                              ((double)(incr * xc) / zoom), ((double)(incr * yc) / zoom));

                mem = 1;
            }
        }


        prev_xc = xc;
        prev_yc = yc;

        draw_angle( );
        break;

    case ButtonRelease:
        switch (event->xbutton.button) {
        case Button1:
        case Button2:

            WHITEAREA(zr);
            if (enf || enf2) {
                enf = 0;
                enf2 = 0;
                xs[0] = xr;
                ys[0] = yr;
                xs[1] = prev_xc;
                ys[1] = prev_yc;

                xz = ((float)(incr * xr) / zoom) * localzoom;
                yz = ((float)(incr * yr) / zoom) * localzoom;
                prev_xzc = ((float)(incr * prev_xc) / zoom) * localzoom;
                prev_yzc = ((float)(incr * prev_yc) / zoom) * localzoom;
                zxs[0] = xz;
                zys[0] = yz;
                zxs[1] = prev_xzc;
                zys[1] = prev_yzc;

                XCopyArea( display, pixmap, XtWindow( radec), gc, 0, voffset, pixmapdim[0], pixmapdim[1], 0, 0);
                redraw_cross( );

                for (z = 0; z < Nsubs; z++) {
                    LINE(radec, POSX(xr, z), POSY(yr, z), POSX(prev_xc, z), POSY(prev_yc, z));
                }

                if (Nsubs >= 2) {
                    XCopyArea( display, integpixmap, XtWindow( integmean), gc, 0, 0, zsizex, zsizey, 0, 0);
                    redraw_zcross( integmean);
                    XCopyArea( display, subsetpixmap, XtWindow( subset), gc, 0, 0, zsizex, zsizey, 0, 0);
                    redraw_zcross( subset);
                    if (subpixmap[0] == 0) {
                        LINE(subset, xr + xoffset, yr + yoffset, prev_xc + xoffset, prev_yc + yoffset);
                    } else {
                        LINE(subset, zxs[0], zys[0], zxs[1], zys[1]);
                    }
                    LINE(integmean, zxs[0], zys[0], zxs[1], zys[1]);
                }


                edit = 1;
            }
            break;
        }
        break;

    case LeaveNotify:
        in = 0;
        break;
    }
}

void spectrum_slice_input( Widget w, XEvent * event)
{
    int x, y, z, d, D, n, N;
    int xc, yc;                 /* current position */
    int zxc, zyc;               /* current position in zoomed subset */
    static int in = 1;
    static int prev_trx, prev_try, enf2 = 0;

    switch (event->type) {
    case EnterNotify:
        in = 1;
        break;
    case ButtonPress:
        switch (event->xbutton.button) {
        case Button1:
            x = event->xbutton.x;
            y = event->xbutton.y;

            if ((w == subset) && (subpixmap[0] == 0)) {

                if ((x < xoffset) || (x >= xoffset + sizex) || (y < yoffset) || (y >= yoffset + sizey))
                    return;
                xr = x - xoffset;
                yr = y - yoffset;
                xz = ((float)(incr * xr) / zoom) * localzoom;
                yz = ((float)(incr * yr) / zoom) * localzoom;
            } else {
                xz = x;
                yz = y;
                xr = zoom * ((float)xz / localzoom) / incr;
                yr = zoom * ((float)yz / localzoom) / incr;
            }


            enf = 1;
            kill_movie( );

            if (!edit) {
                /* initialize previous position */

                prev_xc = xr;
                prev_yc = yr;

                prev_xzc = xz;
                prev_yzc = yz;
            }

            else {
                /* find new origin */
                D = 1E+05;
                for (n = 0; n < 2; n++) {
                    d = sqrt( (float)((ys[n] - yr) * (ys[n] - yr)
                                     + (xs[n] - xr) * (xs[n] - xr)));
                    if (d < D) {
                        D = d;
                        N = n;
                    }
                }

                switch (N) {
                case 0:
                    xr = xs[1];
                    yr = ys[1];
                    xz = zxs[1];
                    yz = zys[1];
                    break;
                case 1:
                    xr = xs[0];
                    yr = ys[0];
                    xz = zxs[0];
                    yz = zys[0];
                    break;
                }

                /* re-initialize previous position */

                prev_xc = xs[N];
                prev_yc = ys[N];

                prev_xzc = zxs[N];
                prev_yzc = zys[N];
            }
            break;
        case Button2:
            prev_trx = event->xbutton.x;
            prev_try = event->xbutton.y;


            enf2 = 1;
            kill_movie( );

            break;
        }
        break;

    case MotionNotify:
        x = event->xmotion.x;
        y = event->xmotion.y;

        if ((!enf && !enf2) || (!in))
            return;

        if ((w == subset) && (subpixmap[0] == 0)) {

            if ((x < xoffset) || (x >= xoffset + sizex) || (y < yoffset) || (y >= yoffset + sizey))
                return;

            xc = x - xoffset;
            yc = y - yoffset;

            zxc = ((float)(incr * xc) / zoom) * localzoom;
            zyc = ((float)(incr * yc) / zoom) * localzoom;
        } else {

            zxc = x;
            zyc = y;

            xc = zoom * ((float)zxc / localzoom) / incr;
            yc = zoom * ((float)zyc / localzoom) / incr;
        }

        if (enf) {
            if (subpixmap[0] == 0) {
                LINE(subset, xr + xoffset, yr + yoffset, prev_xc + xoffset, prev_yc + yoffset);
                LINE(subset, xr + xoffset, yr + yoffset, xc + xoffset, yc + yoffset);
            } else {
                LINE(subset, xz, yz, prev_xzc, prev_yzc);
                LINE(subset, xz, yz, zxc, zyc);
            }

            LINE(integmean, xz, yz, prev_xzc, prev_yzc);
            LINE(integmean, xz, yz, zxc, zyc);

            if ((xc != xr) || (yc != yr)) {
                if (Tolerance < 0)
                    dynamic_slice( ((double)(incr * xr) / zoom), ((double)(incr * yr) / zoom),
                                  ((double)(incr * xc) / zoom), ((double)(incr * yc) / zoom));
                else
                    dynamic_slice_with_blanks( ((double)(incr * xr) / zoom),
                                              ((double)(incr * yr) / zoom),
                                              ((double)(incr * xc) / zoom), ((double)(incr * yc) / zoom));

                mem = 1;
            }
        } else {
            if ((xz + x - prev_trx < 0) || (yz + y - prev_try < 0)
                || (prev_xzc + x - prev_trx < 0)
                || (prev_yzc + y - prev_try < 0))
                return;
            if ((xz + x - prev_trx > zsizex) || (yz + y - prev_try > zsizey)
                || (prev_xzc + x - prev_trx > zsizex)
                || (prev_yzc + y - prev_try > zsizey))
                return;


            if (subpixmap[0] == 0)
                LINE(subset, xr + xoffset, yr + yoffset, prev_xc + xoffset, prev_yc + yoffset);
            else
                LINE(subset, xz, yz, prev_xzc, prev_yzc);

            LINE(integmean, xz, yz, prev_xzc, prev_yzc);

            xz = xz + x - prev_trx;
            yz = yz + y - prev_try;
            xr = zoom * ((float)xz / localzoom) / incr;
            yr = zoom * ((float)yz / localzoom) / incr;

            zxc = prev_xzc + x - prev_trx;
            zyc = prev_yzc + y - prev_try;
            xc = zoom * ((float)zxc / localzoom) / incr;
            yc = zoom * ((float)zyc / localzoom) / incr;

            if (subpixmap[0] == 0)
                LINE(subset, xr + xoffset, yr + yoffset, xc + xoffset, yc + yoffset);
            else
                LINE(subset, xz, yz, zxc, zyc);

            LINE(integmean, xz, yz, zxc, zyc);

            prev_trx = x;
            prev_try = y;

            if (Tolerance < 0)
                dynamic_slice( ((double)(incr * xr) / zoom), ((double)(incr * yr) / zoom),
                              ((double)(incr * xc) / zoom), ((double)(incr * yc) / zoom));
            else
                dynamic_slice_with_blanks( ((double)(incr * xr) / zoom),
                                          ((double)(incr * yr) / zoom), ((double)(incr * xc) / zoom), ((double)(incr * yc) / zoom));

        }
        prev_xc = xc;
        prev_yc = yc;
        prev_xzc = zxc;
        prev_yzc = zyc;
        draw_angle( );
        break;

    case ButtonRelease:
        switch (event->xbutton.button) {
        case Button1:
        case Button2:

            if (enf || enf2) {
                enf = 0;
                enf2 = 0;
                xs[0] = xr;
                ys[0] = yr;
                xs[1] = prev_xc;
                ys[1] = prev_yc;
                zxs[0] = xz;
                zys[0] = yz;
                zxs[1] = prev_xzc;
                zys[1] = prev_yzc;

                XCopyArea( display, pixmap, XtWindow( radec), gc, 0, voffset, pixmapdim[0], pixmapdim[1], 0, 0);
                redraw_cross( );

                for (z = 0; z < Nsubs; z++) {
                    LINE(radec, POSX(xr, z), POSY(yr, z), POSX(prev_xc, z), POSY(prev_yc, z));
                }

                edit = 1;
            }
            break;
        }
        break;

    case LeaveNotify:
        in = 0;
        break;
    }
}

void reset_slice( )
{                                      /* (For the display only) */
    int z;

    if (edit) {
        for (z = 0; z < Nsubs; z++)
            LINE(radec, POSX(xr, z), POSY(yr, z), POSX(prev_xc, z), POSY(prev_yc, z));
        if (Nsubs >= 2) {
            if (subpixmap[0] == 0)
                LINE(subset, xr + xoffset, yr + yoffset, prev_xc + xoffset, prev_yc + yoffset);
            else
                LINE(subset, zxs[0], zys[0], zxs[1], zys[1]);
            LINE(integmean, zxs[0], zys[0], zxs[1], zys[1]);
        }
        edit = 0;
    }
}

void coupe_input( Widget w, XEvent * event)
{
    int x, y, L, z, Y, X;
    static int press1 = 0, prev_z = -1;
    static char works[80];
    int xcoord, ycoord, zcoord;
    float f;
    double uc[3];
    char chainx[80], chainy[80], chainz[80], chainv[80];
    int crossx, crossy, xz, yz;

    switch (event->type) {

    case ButtonPress:
        x = event->xbutton.x;
        y = event->xbutton.y;

        if ((x < (slice_zoomx * slicewidth) / 2 - (slice_zoomx * Np) / 2) ||
            (x >= (slice_zoomx * slicewidth) / 2 + (slice_zoomx * Np) / 2) || (y < 0) || (y >= slice_zoomy * Nsubs))
            return;

        press1 = 1;

        kill_movie( );
        L = (x - ((slice_zoomx * slicewidth) / 2 - (slice_zoomx * Np) / 2))
         / (slice_zoomx);

        z = (Nsubs - 1) - y / (slice_zoomy);

        Y = z / cols;                  /* coordonnees ligne/colonne dans la mosaique */
        X = z - Y * cols;              /* du subset correspondant a la ligne y de la coupe */

        if (prev_z == -1) {
            xcoord = 1;
            ycoord = 1;
            zcoord = 1;
            phys_coord( &xcoord, &ycoord, &zcoord, uc,
                       chainx, chainy, chainz, chainv, strlen( chainx), strlen( chainy), strlen( chainz), strlen( chainv));

            sscanf( chainv, "%e %s", &f, works);
        }

        param( (int)Lgu[L], (npix[1] - 1 - (int)Mgu[L]), z, 0);
        sprintf( dumstr, "%e %s", Buffer[z * Np + L], works);
        XmTextSetString( pixelvalue, dumstr);
        if (Nsubs >= 2)
            XmTextSetString( spixelvalue, dumstr);

        crossx = X * sizex + ((float)(zoom) * Lgu[L]) / incr;
        crossy = Y * sizey - voffset + (int)(((float)(zoom) * Mgu[L]) / incr);

        draw_cross( radec, crossx, crossy);

        if (Nsubs < 2)
            return;

        xz = ((float)(localzoom) * Lgu[L]);
        yz = ((float)(localzoom) * Mgu[L]);
        draw_cross( subset, xz, yz);

        if (z != prev_z) {
            prev_z = z;
            change_tic( z);
            change_pixmap( z);
        }
        break;

    case MotionNotify:
        if (!press1)
            return;
        x = event->xmotion.x;
        y = event->xmotion.y;

        if ((x < (slice_zoomx * slicewidth) / 2 - (slice_zoomx * Np) / 2) ||
            (x >= (slice_zoomx * slicewidth) / 2 + (slice_zoomx * Np) / 2) || (y < 0) || (y >= slice_zoomy * Nsubs))
            return;

        z = (Nsubs - 1) - y / (slice_zoomy);

        Y = z / cols;                  /* coordonnees ligne/colonne dans la mosaique */
        X = z - Y * cols;              /* du subset correspondant a la ligne Y0 de la coupe */

        L = (x - ((slice_zoomx * slicewidth) / 2 - (slice_zoomx * Np) / 2))
         / (slice_zoomx);

        param( (int)Lgu[L], (npix[1] - 1 - (int)Mgu[L]), z, 0);
        sprintf( dumstr, "%e %s", Buffer[z * Np + L], works);
        XmTextSetString( pixelvalue, dumstr);
        if (Nsubs >= 2)
            XmTextSetString( spixelvalue, dumstr);

        crossx = X * sizex + ((float)(zoom) * Lgu[L]) / incr;
        crossy = Y * sizey - voffset + (int)(((float)(zoom) * Mgu[L]) / incr);

        draw_cross( radec, crossx, crossy);

        if (Nsubs < 2)
            return;

        xz = ((float)(localzoom) * Lgu[L]);
        yz = ((float)(localzoom) * Mgu[L]);

        draw_cross( subset, xz, yz);
        if (z != prev_z) {
            prev_z = z;
            change_tic( z);
            change_pixmap( z);
        }
        break;

    case ButtonRelease:
        press1 = 0;
        break;
    }
}

void get_slice_extremities( int extremities[4])
{
    if (mem) {
        extremities[0] = incr * xr / zoom + 1;
        extremities[1] = incr * (sizey - 1 - yr) / zoom + 1;
        extremities[2] = incr * prev_xc / zoom + 1;
        extremities[3] = incr * (sizey - 1 - prev_yc) / zoom + 1;
    } else
        extremities[0] = 0;
}

void slice_after_smooth( )
{
    dynamic_slice_with_blanks( ((double)(incr * xs[0]) / zoom),
                              ((double)(incr * ys[0]) / zoom), ((double)(incr * xs[1]) / zoom), ((double)(incr * ys[1]) / zoom));
}

