/**
 ** clipping.h ---- macros to clip pixels lines and boxes
 **
 ** Copyright (c) 1995 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221
 ** [e-mail: csaba@vuse.vanderbilt.edu]
 **
 ** This file is part of the GRX graphics library.
 **
 ** The GRX graphics library is free software; you can redistribute it
 ** and/or modify it under some conditions; see the "copying.grx" file
 ** for details.
 **
 ** This library is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 **
 **/

#ifndef __CLIPPING_H_INCLUDED__
#define __CLIPPING_H_INCLUDED__

#ifndef __ARITH_H_INCLUDED__
#include "arith.h"
#endif

/*
 * clip pixels and pixel ranges to the clip box
 */
#define clip_xdot_(c,x,when_out) {                                      \
    if((x > c->gc_xcliphi) || (x < c->gc_xcliplo)) { when_out; }        \
}

#define clip_ydot_(c,y,when_out) {                                      \
    if((y > c->gc_ycliphi) || (y < c->gc_ycliplo)) { when_out; }        \
}

#define clip_dot_(c,x,y,when_out) {                                     \
    clip_xdot_(c,x,when_out);                                           \
    clip_ydot_(c,y,when_out);                                           \
}

#define clip_ordxrange_(c,x1,x2,when_out,when_clip) {                   \
    if(x1 > c->gc_xcliphi) { when_out; }                                \
    if(x2 < c->gc_xcliplo) { when_out; }                                \
    if(x1 < c->gc_xcliplo) { x1 = c->gc_xcliplo; when_clip; }           \
    if(x2 > c->gc_xcliphi) { x2 = c->gc_xcliphi; when_clip; }           \
}

#define clip_ordyrange_(c,y1,y2,when_out,when_clip) {                   \
    if(y1 > c->gc_ycliphi) { when_out; }                                \
    if(y2 < c->gc_ycliplo) { when_out; }                                \
    if(y1 < c->gc_ycliplo) { y1 = c->gc_ycliplo; when_clip; }           \
    if(y2 > c->gc_ycliphi) { y2 = c->gc_ycliphi; when_clip; }           \
}

#define clip_xrange_(c,x1,x2,when_out,when_clip) {                      \
    isort(x1,x2);                                                       \
    clip_ordxrange_(c,x1,x2,when_out,when_clip);                        \
}

#define clip_yrange_(c,y1,y2,when_out,when_clip) {                      \
    isort(y1,y2);                                                       \
    clip_ordyrange_(c,y1,y2,when_out,when_clip);                        \
}

#define clip_ordbox_(c,x1,y1,x2,y2,when_out,when_clip) {                \
    clip_ordxrange_(c,x1,x2,when_out,when_clip);                        \
    clip_ordyrange_(c,y1,y2,when_out,when_clip);                        \
}

#define clip_box_(c,x1,y1,x2,y2,when_out,when_clip) {                   \
    clip_xrange_(c,x1,x2,when_out,when_clip);                           \
    clip_yrange_(c,y1,y2,when_out,when_clip);                           \
}

/*
 * clip pixels and pixel ranges to the full context
 */
#define cxclip_xdot_(c,x,when_out) {                                    \
    if((unsigned int)x > (unsigned int)c->gc_xmax) { when_out; }        \
}

#define cxclip_ydot_(c,y,when_out) {                                    \
    if((unsigned int)y > (unsigned int)c->gc_ymax) { when_out; }        \
}

#define cxclip_dot_(c,x,y,when_out) {                                   \
    cxclip_xdot_(c,x,when_out);                                         \
    cxclip_ydot_(c,y,when_out);                                         \
}

#define cxclip_ordxrange_(c,x1,x2,when_out,when_clip) {                 \
    if(x1 > c->gc_xmax) { when_out; }                                   \
    if(x2 < 0)          { when_out; }                                   \
    if(x1 < 0)          { x1 = 0;          when_clip; }                 \
    if(x2 > c->gc_xmax) { x2 = c->gc_xmax; when_clip; }                 \
}

#define cxclip_ordyrange_(c,y1,y2,when_out,when_clip) {                 \
    if(y1 > c->gc_ymax) { when_out; }                                   \
    if(y2 < 0)          { when_out; }                                   \
    if(y1 < 0)          { y1 = 0;          when_clip; }                 \
    if(y2 > c->gc_ymax) { y2 = c->gc_ymax; when_clip; }                 \
}

#define cxclip_xrange_(c,x1,x2,when_out,when_clip) {                    \
    isort(x1,x2);                                                       \
    cxclip_ordxrange_(c,x1,x2,when_out,when_clip);                      \
}

#define cxclip_yrange_(c,y1,y2,when_out,when_clip) {                    \
    isort(y1,y2);                                                       \
    cxclip_ordyrange_(c,y1,y2,when_out,when_clip);                      \
}

#define cxclip_ordbox_(c,x1,y1,x2,y2,when_out,when_clip) {              \
    cxclip_ordxrange_(c,x1,x2,when_out,when_clip);                      \
    cxclip_ordyrange_(c,y1,y2,when_out,when_clip);                      \
}

#define cxclip_box_(c,x1,y1,x2,y2,when_out,when_clip) {                 \
    cxclip_xrange_(c,x1,x2,when_out,when_clip);                         \
    cxclip_yrange_(c,y1,y2,when_out,when_clip);                         \
}

/*
 * clip lines to the clip box
 */
#define clip_hline_(c,x1,x2,y,when_out,when_clip) {                     \
    clip_ydot_(c,y,when_out);                                           \
    clip_xrange_(c,x1,x2,when_out,when_clip);                           \
}

#define clip_vline_(c,x,y1,y2,when_out,when_clip) {                     \
    clip_xdot_(c,x,when_out);                                           \
    clip_yrange_(c,y1,y2,when_out,when_clip);                           \
}

#define clip_line_xmin_(c,x1,y1,x2,y2,when_clip) {                      \
    if(x1 < c->gc_xcliplo) {                                            \
	y1 += irscale((y2 - y1),(c->gc_xcliplo - x1),(x2 - x1));        \
	x1  = c->gc_xcliplo;                                            \
	when_clip;                                                      \
    }                                                                   \
}

#define clip_line_xmax_(c,x1,y1,x2,y2,when_clip) {                      \
    if(x2 > c->gc_xcliphi) {                                            \
	y2 -= irscale((y2 - y1),(x2 - c->gc_xcliphi),(x2 - x1));        \
	x2  = c->gc_xcliphi;                                            \
	when_clip;                                                      \
    }                                                                   \
}

#define clip_line_ymin_(c,x1,y1,x2,y2,when_clip) {                      \
    if(y1 < c->gc_ycliplo) {                                            \
	x1 += irscale((x2 - x1),(c->gc_ycliplo - y1),(y2 - y1));        \
	y1  = c->gc_ycliplo;                                            \
	when_clip;                                                      \
    }                                                                   \
}

#define clip_line_ymax_(c,x1,y1,x2,y2,when_clip) {                      \
    if(y2 > c->gc_ycliphi) {                                            \
	x2 -= irscale((x2 - x1),(y2 - c->gc_ycliphi),(y2 - y1));        \
	y2  = c->gc_ycliphi;                                            \
	when_clip;                                                      \
    }                                                                   \
}

#define clip_line_(c,x1,y1,x2,y2,when_out,when_clip) {                  \
    if(x1 < x2) {                                                       \
	if(x2 < c->gc_xcliplo) { when_out; }                            \
	if(x1 > c->gc_xcliphi) { when_out; }                            \
	clip_line_xmin_(c,x1,y1,x2,y2,when_clip);                       \
	clip_line_xmax_(c,x1,y1,x2,y2,when_clip);                       \
    }                                                                   \
    else {                                                              \
	if(x1 < c->gc_xcliplo) { when_out; }                            \
	if(x2 > c->gc_xcliphi) { when_out; }                            \
	clip_line_xmin_(c,x2,y2,x1,y1,when_clip);                       \
	clip_line_xmax_(c,x2,y2,x1,y1,when_clip);                       \
    }                                                                   \
    if(y1 < y2) {                                                       \
	if(y2 < c->gc_ycliplo) { when_out; }                            \
	if(y1 > c->gc_ycliphi) { when_out; }                            \
	clip_line_ymin_(c,x1,y1,x2,y2,when_clip);                       \
	clip_line_ymax_(c,x1,y1,x2,y2,when_clip);                       \
    }                                                                   \
    else {                                                              \
	if(y1 < c->gc_ycliplo) { when_out; }                            \
	if(y2 > c->gc_ycliphi) { when_out; }                            \
	clip_line_ymin_(c,x2,y2,x1,y1,when_clip);                       \
	clip_line_ymax_(c,x2,y2,x1,y1,when_clip);                       \
    }                                                                   \
}

/*
 * clipping with default actions: outside => return, clipped => nothing
 */
/* some systems have problems with emtpy macro args ... */
#if defined(__GNUC__)
#define CLIP_EMPTY_MACRO_ARG
#endif

#ifndef CLIP_EMPTY_MACRO_ARG
#define CLIP_EMPTY_MACRO_ARG  do ; while(0)
#endif

#define clip_xdot(c,x)                  clip_xdot_(c,x,return)
#define clip_ydot(c,x)                  clip_ydot_(c,y,return)
#define clip_dot(c,x,y)                 clip_dot_(c,x,y,return)
#define clip_ordxrange(c,x1,x2)         clip_ordxrange_(c,x1,x2,return,CLIP_EMPTY_MACRO_ARG)
#define clip_ordyrange(c,y1,y2)         clip_ordyrange_(c,y1,y2,return,CLIP_EMPTY_MACRO_ARG)
#define clip_xrange(c,x1,x2)            clip_xrange_(c,x1,x2,return,CLIP_EMPTY_MACRO_ARG)
#define clip_yrange(c,y1,y2)            clip_yrange_(c,y1,y2,return,CLIP_EMPTY_MACRO_ARG)
#define clip_ordbox(c,x1,y1,x2,y2)      clip_ordbox_(c,x1,y1,x2,y2,return,CLIP_EMPTY_MACRO_ARG)
#define clip_box(c,x1,y1,x2,y2)         clip_box_(c,x1,y1,x2,y2,return,CLIP_EMPTY_MACRO_ARG)

#define cxclip_xdot(c,x)                cxclip_xdot_(c,x,return)
#define cxclip_ydot(c,x)                cxclip_ydot_(c,y,return)
#define cxclip_dot(c,x,y)               cxclip_dot_(c,x,y,return)
#define cxclip_ordxrange(c,x1,x2)       cxclip_ordxrange_(c,x1,x2,return,CLIP_EMPTY_MACRO_ARG)
#define cxclip_ordyrange(c,y1,y2)       cxclip_ordyrange_(c,y1,y2,return,CLIP_EMPTY_MACRO_ARG)
#define cxclip_xrange(c,x1,x2)          cxclip_xrange_(c,x1,x2,return,CLIP_EMPTY_MACRO_ARG)
#define cxclip_yrange(c,y1,y2)          cxclip_yrange_(c,y1,y2,return,CLIP_EMPTY_MACRO_ARG)
#define cxclip_ordbox(c,x1,y1,x2,y2)    cxclip_ordbox_(c,x1,y1,x2,y2,return,CLIP_EMPTY_MACRO_ARG)
#define cxclip_box(c,x1,y1,x2,y2)       cxclip_box_(c,x1,y1,x2,y2,return,CLIP_EMPTY_MACRO_ARG)

#define clip_hline(c,x1,x2,y)           clip_hline_(c,x1,x2,y,return,CLIP_EMPTY_MACRO_ARG)
#define clip_vline(c,x,y1,y2)           clip_vline_(c,x,y1,y2,return,CLIP_EMPTY_MACRO_ARG)
#define clip_line_xmin(c,x1,y1,x2,y2)   clip_line_xmin_(c,x1,y1,x2,y2,CLIP_EMPTY_MACRO_ARG)
#define clip_line_xmax(c,x1,y1,x2,y2)   clip_line_xmax_(c,x1,y1,x2,y2,CLIP_EMPTY_MACRO_ARG)
#define clip_line_ymin(c,x1,y1,x2,y2)   clip_line_ymin_(c,x1,y1,x2,y2,CLIP_EMPTY_MACRO_ARG)
#define clip_line_ymax(c,x1,y1,x2,y2)   clip_line_ymax_(c,x1,y1,x2,y2,CLIP_EMPTY_MACRO_ARG)
#define clip_line(c,x1,y1,x2,y2)        clip_line_(c,x1,y1,x2,y2,return,CLIP_EMPTY_MACRO_ARG)

#endif /* whole file */

