/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2002, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: Slit
*
* %I
* Written by: Kim Lefmann and Henrik M. Roennow
* Date: June 16, 1997
* Origin: Risoe
*
* Rectangular/circular slit
*
* %D
* A simple rectangular or circular slit. You may either
* specify the radius (circular shape), or the rectangular bounds.
* No transmission around the slit is allowed.
*
* Example: Slit(xmin=-0.01, xmax=0.01, ymin=-0.01, ymax=0.01)
*          Slit(xwidth=0.02, yheight=0.02)
*          Slit(radius=0.01)
*
* The Slit will issue a warning if run as "closed"
* 
* %P
* INPUT PARAMETERS
*
* radius: [m]   Radius of slit in the z=0 plane, centered at Origin
* xmin: [m]     Lower x bound 
* xmax: [m]     Upper x bound 
* ymin: [m]     Lower y bound 
* ymax: [m]     Upper y bound 
* xwidth: [m]   Width of slit. Overrides xmin,xmax if they are unset. 
* yheight: [m]  Height of slit. Overrides ymin,ymax if they are unset. 
*
* *
* %E
*******************************************************************************/


DEFINE COMPONENT Slit
DEFINITION PARAMETERS ()
  SETTING PARAMETERS (xmin=UNSET, xmax=UNSET, ymin=UNSET, ymax=UNSET, radius=UNSET, xwidth=UNSET, yheight=UNSET)
OUTPUT PARAMETERS ()
/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */
SHARE
%{
void slit_print_if(int condition, char* level, char* message, char* component){
  if (condition) fprintf(stderr, "Slit: %s: %s: %s\n", component, level, message);
} 
void slit_error_if(int condition, char* message, char* component){
  slit_print_if(condition, "Error", message, component);
  if (condition) exit(-1);
}
void slit_warning_if(int condition, char* message, char* component){
  slit_print_if(condition, "Warning", message, component);
}
%}
DECLARE %{
  char isradial;
%}
INITIALIZE
%{
if (is_unset(radius)){
  isradial=0;
  if (all_set(3, xwidth, xmin, xmax)){
    slit_error_if(xwidth != xmax - xmin, "specifying xwidth, xmin and xmax requires consistent parameters", NAME_CURRENT_COMP);
  } else {
    slit_error_if(is_unset(xwidth) && any_unset(2, xmin, xmax), "specify either xwidth or xmin & xmax", NAME_CURRENT_COMP);
  }
  if (all_set(3, yheight, ymin, ymax)){
    slit_error_if(yheight != ymax - ymin, "specifying yheight, ymin and ymax requires consistent parameters", NAME_CURRENT_COMP);
  } else {
    slit_error_if(is_unset(yheight) && any_unset(2, ymin, ymax), "specify either yheight or ymin & ymax", NAME_CURRENT_COMP);
  }
  if (is_unset(xmin)) { // xmax also unset but xwidth *is* set
    xmax = xwidth/2;
    xmin = -xmax;
  }
  if (is_unset(ymin)) { // ymax also unset but yheight *is* set
    ymax = yheight/2;
    ymin = -ymax;
  }
  slit_warning_if(xmin == xmax || ymin == ymax, "Running with CLOSED rectangular slit - is this intentional?", NAME_CURRENT_COMP);
} else {
  isradial=1;
  slit_error_if(any_set(6, xwidth, xmin, xmax, yheight, ymin, ymax), 
                "specify radius OR width and height parameters", NAME_CURRENT_COMP);
  slit_warning_if(radius == 0., "Running with CLOSED radial slit - is this intentional?", NAME_CURRENT_COMP);
}

%}

TRACE
%{
    PROP_Z0;
    if (!isradial ? (x < xmin || x > xmax || y < ymin || y > ymax) : (x * x + y * y > radius * radius))
      ABSORB;
    else
      SCATTER;
%}

MCDISPLAY
%{
  
  if (is_unset(radius)) {
    double xw, yh;
    xw = (xmax - xmin)/2.0;
    yh = (ymax - ymin)/2.0;
    multiline(3, xmin-xw, (double)ymax, 0.0,
              (double)xmin, (double)ymax, 0.0,
              (double)xmin, ymax+yh, 0.0);
    multiline(3, xmax+xw, (double)ymax, 0.0,
              (double)xmax, (double)ymax, 0.0,
              (double)xmax, ymax+yh, 0.0);
    multiline(3, xmin-xw, (double)ymin, 0.0,
              (double)xmin, (double)ymin, 0.0,
              (double)xmin, ymin-yh, 0.0);
    multiline(3, xmax+xw, (double)ymin, 0.0,
              (double)xmax, (double)ymin, 0.0,
              (double)xmax, ymin-yh, 0.0);
  } else {
    circle("xy",0,0,0,radius);
  }
%}

END
