/*@z15.c:Size Constraints:MinConstraint(), EnlargeToConstraint()@*************/
/*                                                                           */
/*  LOUT: A HIGH-LEVEL LANGUAGE FOR DOCUMENT FORMATTING (VERSION 2.05)       */
/*  COPYRIGHT (C) 1993 Jeffrey H. Kingston                                   */
/*                                                                           */
/*  Jeffrey H. Kingston (jeff@cs.su.oz.au)                                   */
/*  Basser Department of Computer Science                                    */
/*  The University of Sydney 2006                                            */
/*  AUSTRALIA                                                                */
/*                                                                           */
/*  This program is free software; you can redistribute it and/or modify     */
/*  it under the terms of the GNU General Public License as published by     */
/*  the Free Software Foundation; either version 1, or (at your option)      */
/*  any later version.                                                       */
/*                                                                           */
/*  This program 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.  See the            */
/*  GNU General Public License for more details.                             */
/*                                                                           */
/*  You should have received a copy of the GNU General Public License        */
/*  along with this program; if not, write to the Free Software              */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
/*                                                                           */
/*  FILE:         z15.c                                                      */
/*  MODULE:       Size Constraints                                           */
/*  EXTERNS:      MinConstraint(), EnlargeToConstraint(),                    */
/*                ReflectConstraint(), SemiRotateConstraint(),               */
/*                RotateConstraint(), InvScaleConstraint(), Constrained(),   */
/*                EchoConstraint(), DebugConstrained()                       */
/*                                                                           */
/*****************************************************************************/
#include <math.h>
#ifndef M_PI
#define M_PI       3.1415926535897931160E0
#endif

#include "externs"


/*****************************************************************************/
/*                                                                           */
/*  MinConstraint(xc, yc)                                                    */
/*                                                                           */
/*  Replace *xc by the minimum of the two constraints *xc and *yc.           */
/*                                                                           */
/*****************************************************************************/

MinConstraint(xc, yc)
CONSTRAINT *xc, *yc;
{ bc(*xc)  = min(bc(*xc),  bc(*yc));
  bfc(*xc) = min(bfc(*xc), bfc(*yc));
  fc(*xc)  = min(fc(*xc),  fc(*yc));
} /* end MinConstraint */


/*****************************************************************************/
/*                                                                           */
/*  EnlargeToConstraint(b, f, c)                                             */
/*                                                                           */
/*  Enlarge *b,*f to its largest possible value within constraint *c.        */
/*                                                                           */
/*****************************************************************************/

EnlargeToConstraint(b, f, c)
LENGTH *b, *f;  CONSTRAINT *c;
{
  *f = min(bfc(*c) - *b, fc(*c));
} /* end EnlargeToConstraint */


/*@::InvScaleConstraint(), ReflectConstraint(), etc.@*************************/
/*                                                                           */
/*  InvScaleConstraint(yc, sf, xc)                                           */
/*                                                                           */
/*  Scale constraint xc to the inverse of the scale factor sf.               */
/*                                                                           */
/*****************************************************************************/

InvScaleConstraint(yc, sf, xc)
CONSTRAINT *yc;  LENGTH sf;  CONSTRAINT *xc;
{ char buff[10];
  ifdebug(DSC, D, sprintf(buff, "%.3f", (float) sf / SF));
  debug2(DSC, D, "InvScaleConstraint(yc, %s, %s)", buff, EchoConstraint(xc));
  assert( sf > 0, "InvScaleConstraint: sf <= 0!" );
  bc(*yc)  = bc(*xc)  == MAX_LEN ? MAX_LEN : min(MAX_LEN, bc(*xc)  * SF / sf);
  bfc(*yc) = bfc(*xc) == MAX_LEN ? MAX_LEN : min(MAX_LEN, bfc(*xc) * SF / sf);
  fc(*yc)  = fc(*xc)  == MAX_LEN ? MAX_LEN : min(MAX_LEN, fc(*xc)  * SF / sf);
  debug1(DSC, D, "InvScaleConstraint returning %s", EchoConstraint(yc));
} /* end InvScaleConstraint */


/*****************************************************************************/
/*                                                                           */
/*  ReflectConstraint(xc, yc)                                                */
/*                                                                           */
/*  Set xc to the constraint which is yc with its back and forward reversed. */
/*                                                                           */
/*****************************************************************************/

#define ReflectConstraint(xc, yc)  SetConstraint(xc, fc(yc), bfc(yc), bc(yc))


/*****************************************************************************/
/*                                                                           */
/*  static SemiRotateConstraint(xc, u, v, angle, yc)                         */
/*                                                                           */
/*  Used by RotateConstraint to calculate one rotated constraint.            */
/*                                                                           */
/*****************************************************************************/

static SemiRotateConstraint(xc, u, v, angle, yc)
CONSTRAINT *xc;  LENGTH u, v;  float angle; CONSTRAINT *yc;
{ float cs, sn;  char buff[20];
  ifdebug(DSC, D, sprintf(buff, "%.1f", angle * 360.0 / (2 * M_PI)));
  debug4(DSC, D, "SemiRotateConstraint(xc, %s, %s, %sd, %s",
    EchoLength(u), EchoLength(v), buff, EchoConstraint(yc));
  cs = cos(angle);  sn = sin(angle);
  if( fabs(cs) < 1e-6 )
    SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
  else
    SetConstraint(*xc,
      min(MAX_LEN, (bc(*yc) - u * sn) / cs),
      min(MAX_LEN, (bfc(*yc) - u * sn - v * sn) / cs),
      min(MAX_LEN, (fc(*yc) - v * sn) / cs) );
  debug1(DSC, D, "SemiRotateConstraint returning %s", EchoConstraint(xc));
} /* end SemiRotateConstraint */


/*@::RotateConstraint()@******************************************************/
/*                                                                           */
/*  RotateConstraint(c, y, angle, hc, vc, dim)                               */
/*                                                                           */
/*  Take the object angle @Rotate y, which is supposed to be constrained     */
/*  horizontally by hc and vertically by vc, and determine a constraint      */
/*  (either horizontal or vertical, depending on dim) for y.                 */
/*                                                                           */
/*  The constraint returned is a trigonometric function of all these         */
/*  parameters, including the present size of y in dimension 1-dim.          */
/*                                                                           */
/*****************************************************************************/

RotateConstraint(c, y, angle, hc, vc, dim)
CONSTRAINT *c;  OBJECT y;  LENGTH angle;  CONSTRAINT *hc, *vc;  int dim;
{ CONSTRAINT c1, c2, c3, dc;  float theta, psi;
  char buff[20];
  ifdebug(DSC, D, sprintf(buff, "%.1f", (float) angle / DG ));
  debug4(DSC, D, "RotateConstraint(c, y, %sd, %s, %s, %s)",
	buff, EchoConstraint(hc), EchoConstraint(vc), dimen(dim));

  /* work out angle in radians between 0 and 2*PI */
  theta = (float) angle * 2 * M_PI / (float) (DG * 360);
  while( theta < 0 ) theta += 2 * M_PI;
  while( theta >= 2 * M_PI ) theta -= 2 * M_PI;
  assert( 0 <= theta && theta <= 2 * M_PI, "RotateConstraint: theta!" );

  /* determine theta, c1, and c2 depending on which quadrant we are in */
  if( theta <= M_PI / 2.0 )   /* first quadrant */
  { theta = theta;
    CopyConstraint(c1, *hc);
    CopyConstraint(c2, *vc);
  }
  else if ( theta <= M_PI )   /* second quadrant */
  { theta -= M_PI / 2.0;
    ReflectConstraint(c1, *vc);
    CopyConstraint(c2, *hc);
  }
  else if ( theta <= 3.0 * M_PI / 2.0 )   /* third quadrant */
  { theta -= M_PI;
    ReflectConstraint(c1, *hc);
    ReflectConstraint(c2, *vc);
  }
  else /* fourth quadrant */
  { theta -= 3.0 * M_PI / 2.0;
    CopyConstraint(c1, *vc);
    ReflectConstraint(c2, *hc);
  }
  psi = M_PI / 2.0 - theta;
  debug2(DSC, D, "  c1: %s;  c2: %s", EchoConstraint(&c1), EchoConstraint(&c2));

  /* return the minimum of the two constraints, rotated */
  if( dim == COL )
  { SemiRotateConstraint(c, back(y, ROW), fwd(y, ROW), theta, &c1);
    ReflectConstraint(c3, c2);
    SemiRotateConstraint(&dc, fwd(y, ROW), back(y, ROW), psi, &c3);
    MinConstraint(c, &dc);
  }
  else
  { SemiRotateConstraint(c, back(y, COL), fwd(y, COL), psi, &c1);
    SemiRotateConstraint(&dc, fwd(y, COL), back(y, COL), theta, &c2);
    MinConstraint(c, &dc);
  }

  debug1(DSC, D, "RotateConstraint returning %s", EchoConstraint(c));
} /* end RotateConstraint */


/*@::CatConstrained()@********************************************************/
/*                                                                           */
/*  static CatConstrained(x, xc, ratm, y, dim)                               */
/*                                                                           */
/*  Calculate the size constraint of object x, as for Constrained below.     */
/*  y is the enclosing VCAT etc. object;  ratm is TRUE if a ^ lies after     */
/*  x anywhere.  dim is COL or ROW.                                          */
/*                                                                           */
/*  The meaning of the key variables is as follows:                          */
/*                                                                           */
/*  be       The amount by which back(x, dim) can increase from zero         */
/*           without having any impact on size(y, dim).  Thereafter,         */
/*           any increase causes an equal increase in size(y, dim).          */
/*                                                                           */
/*  fe       The amount by which fwd(x, dim) can increase from zero          */
/*           without having any impact on size(y, dim).  Thereafter,         */
/*           any increase causes an equal increase in size(y, dim).          */
/*                                                                           */
/*  backy,   The value that back(y, dim) and fwd(y, dim) would have if x     */
/*  fwdy     was definite with size 0,0.  They will in general be larger     */
/*           than the present values if x is indefinite, and smaller         */
/*           if x is definite, although it depends on marks and gaps.        */
/*                                                                           */
/*****************************************************************************/

static CatConstrained(x, xc, ratm, y, dim)
OBJECT x;  CONSTRAINT *xc; BOOLEAN ratm;  OBJECT y;  int dim;
{ int side;			/* the size of y that x is on: BACK, ON, FWD */
  CONSTRAINT yc;		/* constraints on y                          */
  LENGTH backy, fwdy;		/* back(y), fwd(y) would be if x was (0, 0)  */
  LENGTH be, fe;		/* amount back(x), fwd(x) can be for free    */
  LENGTH beffect, feffect;	/* scratch variables for calculations        */
  LENGTH seffect;		/* scratch variables for calculations        */
  OBJECT link, sg, pg;	/* link to x, its successor and predecessor  */
  OBJECT prec_def, sd;	/* definite object preceding (succeeding) x  */
  int tb, tbf, tf, tbc, tbfc, tfc, mxy, myz;

  Constrained(y, &yc, dim);
  if( constrained(yc) )
  {
    /* find the link of x, and its neighbours and their links */
    link = UpDim(x, dim);
    SetNeighbours(link, ratm, &pg, &prec_def, &sg, &sd, &side);

    /* amount of space available at x without changing the size of y */
    be = pg == nil ? 0 : ExtraGap(fwd(prec_def, dim), 0, &gap(pg), BACK);
    fe = sg == nil ? 0 : ExtraGap(0, back(sd, dim),      &gap(sg), FWD);

    if( is_indefinite(type(x)) )
    {
      /* insert two lengths and delete one */
      beffect = pg == nil ? 0 : MinGap(fwd(prec_def, dim), 0, 0, &gap(pg));
      feffect = sg == nil ? 0 : MinGap(0, back(sd,dim), fwd(sd,dim), &gap(sg));
      seffect = pg == nil ?
	  sg == nil ? 0 : back(sd, dim) :
	  sg == nil ? fwd(prec_def, dim) :
	    MinGap(fwd(prec_def, dim), back(sd, dim), fwd(sd, dim), &gap(sg));

      switch( side )
      {
	case BACK:	backy = back(y, dim) + beffect + feffect - seffect;
			fwdy  = fwd(y, dim);
			break;

	case ON:	/* must be first, other cases prohibited */
			backy = 0;
			fwdy = fwd(y, dim) + feffect;
			break;

	case FWD:	backy = back(y, dim);
			fwdy  = fwd(y, dim) + beffect + feffect - seffect;
			break;
      }
    }

    else /* x is definite */

    { beffect = pg == nil ? back(x, dim) :
	MinGap(fwd(prec_def, dim), back(x,dim), fwd(x,dim), &gap(pg)) -
	MinGap(fwd(prec_def, dim), 0,           0,          &gap(pg));

      feffect = sg == nil ? fwd(x, dim) :
	MinGap(fwd(x, dim), back(sd, dim), fwd(sd, dim), &gap(sg)) -
	MinGap(0,           back(sd, dim), fwd(sd, dim), &gap(sg));

      switch( side )
      {
	case BACK:	backy = back(y, dim) - beffect - feffect;
			fwdy  = fwd(y, dim);
			break;

	case ON:	backy = back(y, dim) - beffect;
			fwdy  = fwd(y, dim)  - feffect;
			break;

	case FWD:	backy = back(y, dim);
			fwdy  = fwd(y, dim) - beffect - feffect;
			break;
      }
    }

    debug5(DSC, DDD, "side: %s, backy: %s, fwdy: %s, be: %s, fe: %s",
		Image(side), EchoLength(backy), EchoLength(fwdy),
		EchoLength(be), EchoLength(fe) );

    if( !FitsConstraint(backy, fwdy, yc) )
      SetConstraint(*xc, -1, -1, -1);
    else switch( side )
    {

      case BACK:
	
	tbc = bc(yc) == MAX_LEN ? MAX_LEN : bc(yc) - backy;
	tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
	mxy = min(tbc, tbfc);
	tb  = min(MAX_LEN, be + mxy);
	tbf = min(MAX_LEN, be + fe + mxy);
	tf  = min(MAX_LEN, fe + mxy);
	SetConstraint(*xc, tb, tbf, tf);
	break;


      case ON:
	
	tbc = bc(yc) == MAX_LEN ? MAX_LEN : bc(yc) - backy;
	tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
	tfc = fc(yc) == MAX_LEN ? MAX_LEN : fc(yc) - fwdy;
	mxy = min(tbc, tbfc);
	myz = min(tfc, tbfc);
	tb  = min(MAX_LEN, be + mxy);
	tbf = min(MAX_LEN, be + fe + tbfc);
	tf  = min(MAX_LEN, fe + myz);
	SetConstraint(*xc, tb, tbf, tf);
	break;
	

      case FWD:

	tfc = fc(yc) == MAX_LEN ? MAX_LEN : fc(yc) - fwdy;
	tbfc = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - backy - fwdy;
	mxy = min(tfc, tbfc);
	tb  = min(MAX_LEN, be + mxy);
	tbf = min(MAX_LEN, be + fe + mxy);
	tf  = min(MAX_LEN, fe + mxy);
	SetConstraint(*xc, tb, tbf, tf);
	break;
	
    }
  } /* end if( constrained ) */
  else SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
} /* end CatConstrained */


/*@::Constrained()@***********************************************************/
/*                                                                           */
/*  Constrained(x, xc, dim)                                                  */
/*                                                                           */
/*  Calculate the size constraint of object x, and return it in *xc.         */
/*                                                                           */
/*****************************************************************************/

Constrained(x, xc, dim)
OBJECT x;  CONSTRAINT *xc;  int dim;
{ OBJECT y, link, lp, rp, z, tlink, g;  CONSTRAINT yc, hc, vc;
  BOOLEAN ratm;  LENGTH xback, xfwd;  int tb, tf, tbf, tbc, tfc;
  debug2(DSC, DD, "[ Constrained( %s, xc, %s )", EchoObject(x), dimen(dim));
  assert( Up(x) != x, "Constrained: x has no parent!" );

  /* find y, the parent of x */
  link = UpDim(x, dim);  ratm = FALSE;
  for( tlink = NextDown(link);  type(tlink) == LINK;  tlink = NextDown(tlink) )
  { Child(g, tlink);
    if( type(g) == GAP_OBJ && mark(gap(g)) )  ratm = TRUE;
  }
  y = tlink;
  debug1(DSC, DDD, "parent y = %s", Image(type(y)));
  ifdebug(DSC, DDD, DebugObject(y));

  switch( type(y) )
  {
    case GRAPHIC:
    case ONE_COL:
    case ONE_ROW:
    case HCONTRACT:
    case VCONTRACT:
    case HEXPAND:
    case VEXPAND:
    case PADJUST:
    case HADJUST:
    case VADJUST:
    case SPLIT:
    
      Constrained(y, xc, dim);
      break;


    case VSCALE:
    case HSCALE:
    
      if( (dim == COL) != (type(y) == HSCALE) )  Constrained(y, xc, dim);
      else SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
      break;


    case SCALE:

      Constrained(y, &yc, dim);
      InvScaleConstraint(xc,
	dim == COL ? bc(constraint(y)) : fc(constraint(y)), &yc);
      break;


    case ROTATE:
    
      Constrained(y, &hc, COL);  Constrained(y, &vc, ROW);
      RotateConstraint(xc, x, sparec(constraint(y)), &hc, &vc, dim);
      break;


    case WIDE:
    case HIGH:
    
      Constrained(y, xc, dim);
      if( (type(y)==WIDE) == (dim==COL) )  MinConstraint(xc, &constraint(y));
      break;


    case HEAD:
    
      if( dim == ROW ) SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
      else
      {	CopyConstraint(yc, constraint(y));
	debug1(DSC, DD, "  head: %s; val is:", EchoConstraint(&yc));
	ifdebug(DSC, DD, DebugObject(y));
	goto REST_OF_HEAD;   /* a few lines down */
      }
      break;


    case COL_THR:
    case ROW_THR:

      assert( (type(y)==COL_THR) == (dim==COL), "Constrained: COL_THR!" );
      Constrained(y, &yc, dim);
      tb = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - fwd(y, dim);
      tb = min(bc(yc), tb);
      tf = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - back(y, dim);
      tf = min(fc(yc), tf);
      SetConstraint(*xc, tb, bfc(yc), tf);
      break;


    case VCAT:
    case HCAT:
    case ACAT:
    
      if( (type(y)==VCAT) == (dim==ROW) )
      {	CatConstrained(x, xc, ratm, y, dim);
	break;
      }
      Constrained(y, &yc, dim);
      if( !constrained(yc) )  SetConstraint(*xc, MAX_LEN, MAX_LEN, MAX_LEN);
      else
      {
	REST_OF_HEAD:
	/* let lp and rp be the links of the gaps delimiting */
	/* the components joined to x (or parent if no such) */
	for( lp = PrevDown(link);  lp != y;  lp = PrevDown(lp) )
	{ Child(z, lp);
	  if( type(z) == GAP_OBJ && !join(gap(z)) )  break;
	}
	for( rp = NextDown(link);  rp != y;  rp = NextDown(rp) )
	{ Child(z, rp);
	  if( type(z) == GAP_OBJ && !join(gap(z)) )  break;
	}
	if( lp == y && rp == y && !(type(y) == HEAD && seen_nojoin(y)) )
	{
	  /* if whole object is joined, do this */
          tb = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - fwd(y, dim);
          tb = min(bc(yc), tb);
          tf = bfc(yc) == MAX_LEN ? MAX_LEN : bfc(yc) - back(y, dim);
          tf = min(fc(yc), tf);
          SetConstraint(*xc, tb, bfc(yc), tf);
	}
	else
	{
	  /* if // or || is present, do this */
	  xback = xfwd = 0;
	  for(link = NextDown(lp); link != rp;  link = NextDown(link) )
	  { Child(z, link);
	    if( type(z) == GAP_OBJ || is_index(type(z)) )  continue;
	    xback = max(xback, back(z, dim));  xfwd = max(xfwd, fwd(z, dim));
	  }
	  debug2(DSC, DD, "  lp != rp; xback,xfwd = %s,%s",
			EchoLength(xback), EchoLength(xfwd));
	  tbf = min(bfc(yc), fc(yc));
	  tbc = tbf == MAX_LEN ? MAX_LEN : tbf - xfwd;
	  tfc = tbf == MAX_LEN ? MAX_LEN : tbf - xback;
	  SetConstraint(*xc, tbc, tbf, tfc);
	}
      }
      break;


    default:  Error(INTERN, &fpos(y), "Constrained: %s", Image(type(y)) );
	      break;
  }
  debug1(DSC, DD, "] Constrained returning %s", EchoConstraint(xc));
} /* end Constrained */


/*@::EchoConstraint(), DebugConstrained()@************************************/
/*                                                                           */
/*  FULL_CHAR *EchoConstraint(c)                                             */
/*                                                                           */
/*  Returns a string showing constraint *c, in centimetres.                  */
/*                                                                           */
/*****************************************************************************/
#if DEBUG_ON

FULL_CHAR *EchoConstraint(c)
CONSTRAINT *c;
{ static char str[2][40];
  static int i = 0;
  i = (i+1) % 2;
  sprintf(str[i], "<");
  if( bc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF, ");
  else sprintf(&str[i][strlen(str[i])], "%.3fc, ", (float) bc(*c)/CM);
  if( bfc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF, ");
  else sprintf(&str[i][strlen(str[i])], "%.3fc, ", (float) bfc(*c)/CM);
  if( fc(*c)==MAX_LEN )  sprintf(&str[i][strlen(str[i])], "INF>");
  else sprintf(&str[i][strlen(str[i])], "%.3fc>", (float) fc(*c)/CM);
  return AsciiToFull(str[i]);
} /* end EchoConstraint */


/*****************************************************************************/
/*                                                                           */
/*  DebugConstrained(x)                                                      */
/*                                                                           */
/*  Calculate and print the constraints of all closures lying within         */
/*  sized object x.                                                          */
/*                                                                           */
/*****************************************************************************/

DebugConstrained(x)
OBJECT x;
{ OBJECT y, link;
  CONSTRAINT c;
  debug1(DSC, DDD, "DebugConstrained( %s )", EchoObject(x) );
  switch( type(x) )
  {

    case CROSS:
    case ROTATE:
    case INCGRAPHIC:
    case SINCGRAPHIC:
    case GRAPHIC:
    case WORD:
    case QWORD:
    
      break;


    case CLOSURE:
    
      Constrained(x, &c, COL);
      debug2(DSC, D, "Constrained( %s, &c, COL ) = %s",
	EchoObject(x), EchoConstraint(&c));
      Constrained(x, &c, ROW);
      debug2(DSC, D, "Constrained( %s, &c, ROW ) = %s",
	EchoObject(x), EchoConstraint(&c));
      break;


    case SPLIT:
    
      link = DownDim(x, COL);  Child(y, link);
      DebugConstrained(y);
      break;


    case HEAD:
    case ONE_COL:
    case ONE_ROW:
    case HCONTRACT:
    case VCONTRACT:
    case HEXPAND:
    case VEXPAND:
    case PADJUST:
    case HADJUST:
    case VADJUST:
    case HSCALE:
    case VSCALE:
    case SCALE:
    case WIDE:
    case HIGH:
    
      link = Down(x);  Child(y, link);
      DebugConstrained(y);
      break;


    case COL_THR:
    case VCAT:
    case HCAT:
    case ACAT:
    
      for( link = Down(x);  link != x;  link =NextDown(link) )
      {	Child(y, link);
	if( type(y) != GAP_OBJ && !is_index(type(y)) )  DebugConstrained(y);
      }
      break;


    default:
    
      Error(INTERN, &fpos(x), "DebugConstrained: type(x)= %s", Image(type(x)) );
      break;

  }
  debug0(DSC, DDD, "DebugConstrained returning.");
} /* end DebugConstrained */
#endif
