Metropoli BBS
VIEWER: overload.c MODE: TEXT (ASCII)
/*****************************************************************************
*   "Irit" - the 3d polygonal solid modeller.				     *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Mar. 1990   *
******************************************************************************
*   Module to handle overloaded operators for the input parser module.	     *
* Note this module should be accessed by Input Parser only (InptPrsr.c).     *
*****************************************************************************/

#ifdef __MSDOS__
#include <alloc.h>
#endif /* __MSDOS__ */

#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
#include "program.h"
#include "allocate.h"
#include "booleang.h"
#include "freeform.h"
#include "geomat3d.h"
#include "inptprsg.h"
#include "inptprsl.h"
#include "objects.h"
#include "overload.h"

/* The following table help to decide if the operand are legal for the given */
/* operator. 5 entries for PLUS, MINUS, MULT, DIV, POWER. Each entry is a    */
/* square matrix of number of object types by number of object types:	     */

static IritExprType OverLoadDiadicTable[5][9][9] =
/*    POLY_EXPR	 NUMERIC_EXPR  VECTOR_EXPR   MATRIX_EXPR  CURVE_EXPR  SURFACE_EXPR   STRING_EXPR  OLST_EXPR    CTLPT_EXPR */
{ { /* PLUS */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      VECTOR_EXPR,  NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     MATRIX_EXPR, NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     NO_EXPR,	  CURVE_EXPR, NO_EXPR,       NO_EXPR,     NO_EXPR,     CURVE_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     OLST_EXPR,   NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     CURVE_EXPR, NO_EXPR,       NO_EXPR,     NO_EXPR,     CURVE_EXPR } },

  { /* MINUS */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      VECTOR_EXPR,  NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     MATRIX_EXPR, NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     NO_EXPR,	  NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR } },

  { /* MULT */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     POLY_EXPR,   NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, VECTOR_EXPR,  MATRIX_EXPR, NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 VECTOR_EXPR,  NUMERIC_EXPR, VECTOR_EXPR, NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { POLY_EXPR, MATRIX_EXPR,  VECTOR_EXPR,  MATRIX_EXPR, CURVE_EXPR, SURFACE_EXPR,  NO_EXPR,     OLST_EXPR,   NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     CURVE_EXPR,  NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     SURFACE_EXPR,NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     OLST_EXPR,   NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR } },

  { /* DIV */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     NO_EXPR,	  NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR } },

  { /* POWER */
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NUMERIC_EXPR, NO_EXPR,	     MATRIX_EXPR, NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 MATRIX_EXPR,  NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,	 NO_EXPR,      NO_EXPR,	     NO_EXPR,	  NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { POLY_EXPR, NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    POLY_EXPR,     NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR },
    { NO_EXPR,   NO_EXPR,      NO_EXPR,	     NO_EXPR,     NO_EXPR,    NO_EXPR,       NO_EXPR,     NO_EXPR,     NO_EXPR } },
};

/* The following table help to decide if the operand are legal for the given */
/* operator. 1 entry for UNARMINUS. Each entry is a linear vector of length  */
/* of number of object types:						     */

static IritExprType OverLoadMonadicTable[1][9] =
/* POLY_EXPR NUMERIC_EXPR  VECTOR_EXPR	MATRIX_EXPR  CURVE_EXPR  SURFACE_EXPR  STRING_EXPR  OLST_EXPR  CTLPT_EXPR */
{ /* UNARMINUS */
  { POLY_EXPR, NUMERIC_EXPR, VECTOR_EXPR, MATRIX_EXPR, CURVE_EXPR, SURFACE_EXPR, NO_EXPR,     NO_EXPR,   NO_EXPR }
};

static int OverLoadTypeCheckAux(int Operator, IritExprType Right,
				IritExprType Left, IritExprType *Result);
static ObjectStruct *ConvSrfToPolys(ParseTree *Srf);

/*****************************************************************************
*   Routine to perform type checking on the overloaded operators. Returns    *
* TRUE if legal, and set Result to returned object type.		     *
*   Allows multiple types (I.e. VECTOR_EXPR | MATRIX_EXPR is legal input).   *
*   Note output Result may be multiple types as well is a such case.	     *
*****************************************************************************/
int OverLoadTypeCheck(int Operator, IritExprType Right, IritExprType Left,
							IritExprType *Result)
{
    int i, j, NumRightTypes, NumLeftTypes;
    IritExprType TmpResult;

    /* Compute how many types are feasible here (input). */
    for (i = 1, NumRightTypes = 0; i < ERROR_EXPR; i <<= 1)
	NumRightTypes += (i & Right) != 0;
    for (i = 1, NumLeftTypes = 0; i < ERROR_EXPR; i <<= 1)
	NumLeftTypes += (i & Left) != 0;

    if (NumLeftTypes < 1 || NumRightTypes < 1)
	return FALSE;
    else if (NumLeftTypes == 1 && NumRightTypes == 1)
	return OverLoadTypeCheckAux(Operator, Right, Left, Result);
    else {
	/* More than one type in the input - compute union of the output     */
    	/* types and return the union.					     */
	*Result = 0;
    	for (i = 1; i < ERROR_EXPR; i <<= 1) if ((i & Right) != 0)
    	    for (j = 1; j < ERROR_EXPR; j <<= 1) if ((j & Left) != 0) {
		if (!OverLoadTypeCheckAux(Operator,
					  (IritExprType) i,
					  (IritExprType) j,
					  &TmpResult))
		    return FALSE;
		*Result |= TmpResult;
    	    }
	return TRUE;
    }
}

/*****************************************************************************
*   Routine to perform type checking on the overloaded operators. Returns    *
* TRUE if legal, and set Result to returned object type.		     *
*   Assumes a single type (I.e. VECTOR_EXPR | MATRIX_EXPR is illegal input). *
*****************************************************************************/
static int OverLoadTypeCheckAux(int Operator, IritExprType Right,
				IritExprType Left, IritExprType *Result)
{
    int i, IRight, ILeft;

    for (i = 1, IRight = 0; i < Right; i <<= 1, IRight++);
    for (i = 1, ILeft  = 0; i < Left;  i <<= 1, ILeft++);

    switch (Operator) {
	case PLUS:
	case MINUS:
	case MULT:
	case DIV:
	case POWER:
	    *Result = OverLoadDiadicTable[Operator - OPERATORS_OFFSET]
					 [IRight][ILeft];
	    return *Result != NO_EXPR;
	case UNARMINUS:
	    *Result = OverLoadMonadicTable[0][IRight];
	    return *Result != NO_EXPR;
	default:
	    FatalError("OverLoadTypeCheck: undefined operator\n");
    }
    return FALSE;				    /* Makes warning silent. */
}

/*****************************************************************************
*   Routine to evaluate	an monadic or diadic expression. It is assumed the   *
* two operands are valid for the given expression - a test which can be made *
* using OverLoadTypeCheck routine (see above). returned pointer to node with *
* the result, NULL in case of error (should not happen actually).	     *
* Root holds the simple sub-expression (Root has the operator). PObj holds   *
* all the currently defined objects available in the system. IError & CError *
* will be set to relevant error if was one.				     *
*****************************************************************************/
ParseTree *OverLoadEvalOper(ParseTree *Root, ParseTree *TempR,
		ParseTree *TempL, InptPrsrEvalErrType *IError, char *CError)
{
    int i,
	OperReversed = FALSE;
    RealType R;
    ParseTree *Temp,
	*RetVal = Root;
    ObjectStruct *TempLObj, *TempRObj;

    switch (Root->NodeKind) {		      /* Dies if undefined operator. */
	case PLUS:
	case MINUS:
	case MULT:
	case DIV:
	case POWER:
	    if (TempR == NULL || TempL == NULL) return NULL;	   /* Error! */
	    break;

	case UNARMINUS:
	    if (TempR == NULL) return NULL;			   /* Error! */
	    break;

	default:
	    FatalError("OverLoadEvalOper: Undefined operator\n");
    }

    /* Make TempL be bigger, so we need handle less cases. */
    if (Root -> NodeKind != UNARMINUS &&
	((int) TempR -> ObjType) > ((int) TempL -> ObjType)) {
	Temp = TempR;
	TempR = TempL;
	TempL = Temp;

	OperReversed = TRUE;
    }

    switch (Root->NodeKind) {
	case PLUS:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {
		Root->ObjType = NUMERIC_OBJ;
		Root->U.R = TempL->U.R + TempR->U.R;
	    }
	    else if (IS_VEC_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root->ObjType = VECTOR_OBJ;
		Root->U.PObj = AllocObject("", VECTOR_OBJ, NULL);
		PT_ADD(Root->U.PObj->U.Vec,
			TempL->U.PObj->U.Vec, TempR->U.PObj->U.Vec);
	    }
	    else if (IS_MAT_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root->ObjType = MATRIX_OBJ;
		Root->U.PObj = AllocObject("", MATRIX_OBJ, NULL);
                MatAddTwo4by4(Root->U.PObj->U.Mat,
			TempL->U.PObj->U.Mat, TempR->U.PObj->U.Mat);
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);
		Root->ObjType = POLY_OBJ;
		Root->U.PObj = BooleanOR(TempLObj, TempRObj);
		if (Root->U.PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", PLUS);
		    RetVal = NULL;
		}
	    }
	    else if (IS_OLST_NODE(TempR) && IS_OLST_NODE(TempL)) {
		Root->ObjType = OBJ_LIST_OBJ;
	    	Root->U.PObj = AppendLists(TempL->U.PObj, TempR->U.PObj);
	    }
	    else if ((IS_CTLPT_NODE(TempR) || IS_CRV_NODE(TempR)) &&
		     (IS_CTLPT_NODE(TempL) || IS_CRV_NODE(TempL))) {
		Root->ObjType = CURVE_OBJ;
		if (OperReversed)
		    Root->U.PObj = MergeCurvesAndCtlPoints(TempR->U.PObj,
							   TempL->U.PObj);
		else
		    Root->U.PObj = MergeCurvesAndCtlPoints(TempL->U.PObj,
							   TempR->U.PObj);
	    }
	    else
		RetVal = NULL;
	    break;
	case MINUS:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {
		Root->ObjType = NUMERIC_OBJ;
		Root->U.R = TempL->U.R - TempR->U.R;
	    }
	    else if (IS_VEC_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root->ObjType = VECTOR_OBJ;
		Root->U.PObj = AllocObject("", VECTOR_OBJ, NULL);
		PT_SUB(Root->U.PObj->U.Vec,
			TempL->U.PObj->U.Vec, TempR->U.PObj->U.Vec);
	    }
	    else if (IS_MAT_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root->ObjType = MATRIX_OBJ;
		Root->U.PObj = AllocObject("", MATRIX_OBJ, NULL);
                MatSubTwo4by4(Root->U.PObj->U.Mat,
			TempL->U.PObj->U.Mat, TempR->U.PObj->U.Mat);
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);
		Root->ObjType = POLY_OBJ;
		Root->U.PObj = BooleanSUB(TempLObj, TempRObj);
		if (Root->U.PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", MINUS);
		    RetVal = NULL;
		}
	    }
	    else
		RetVal = NULL;
	    break;
	case MULT:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {
		Root->ObjType = NUMERIC_OBJ;
		Root->U.R = TempL->U.R * TempR->U.R;
	    }
	    else if (IS_VEC_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root->ObjType = NUMERIC_OBJ;
		Root->U.R = DOT_PROD(TempL->U.PObj->U.Vec,
				     TempR->U.PObj->U.Vec);
	    }
	    else if (IS_MAT_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root->ObjType = MATRIX_OBJ;
		Root->U.PObj = AllocObject("", MATRIX_OBJ, NULL);
                MatMultTwo4by4(Root->U.PObj->U.Mat,
			TempL->U.PObj->U.Mat, TempR->U.PObj->U.Mat);
	    }
	    else if (IS_NUM_NODE(TempR) && IS_VEC_NODE(TempL)) {
		Root->ObjType = VECTOR_OBJ;
		Root->U.PObj = AllocObject("", VECTOR_OBJ, NULL);
		PT_COPY(Root->U.PObj->U.Vec, TempL->U.PObj->U.Vec);
		PT_SCALE(Root->U.PObj->U.Vec, TempR->U.R);
	    }
	    else if (IS_NUM_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root->ObjType = MATRIX_OBJ;
		Root->U.PObj = AllocObject("", MATRIX_OBJ, NULL);
		MatScale4by4(Root->U.PObj->U.Mat,
					TempL->U.PObj->U.Mat, &TempR->U.R);
	    }
	    else if (IS_POLY_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root->U.PObj = TransformObject(TempR->U.PObj,
					       TempL->U.PObj->U.Mat);
		Root->ObjType = POLY_OBJ;
	    }
	    else if ((IS_MAT_NODE(TempR) && IS_CRV_NODE(TempL)) ||
		     (IS_MAT_NODE(TempR) && IS_SRF_NODE(TempL)) ||
		     (IS_MAT_NODE(TempR) && IS_OLST_NODE(TempL))) {
		Root->U.PObj = TransformObject(TempL->U.PObj,
					       TempR->U.PObj->U.Mat);
		Root->ObjType = Root->U.PObj->ObjType;
	    }
	    else if (IS_VEC_NODE(TempR) && IS_MAT_NODE(TempL)) {
		Root->ObjType = VECTOR_OBJ;
		Root->U.PObj = AllocObject("", VECTOR_OBJ, NULL);
		MatMultVecby4by4(Root->U.PObj->U.Vec,
				 TempR->U.PObj->U.Vec, TempL->U.PObj->U.Mat);
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);
		Root->ObjType = POLY_OBJ;
		Root->U.PObj = BooleanAND(TempLObj, TempRObj);
		if (Root->U.PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", MULT);
		    RetVal = NULL;
		}
	    }
	    else
		RetVal = NULL;
	    break;
	case DIV:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {  /* Numeric div. */
		Root->ObjType = NUMERIC_OBJ;
		if (Root->Right->U.R != 0.0) {
		    Root->U.R = TempL->U.R / TempR->U.R;
		}
		else {
		    *IError = IE_ERR_DIV_BY_ZERO;
		    strcpy(CError, "/");
		    RetVal = NULL;
		}
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);
		Root->ObjType = POLY_OBJ;
		Root->U.PObj = BooleanCUT(TempLObj, TempRObj);
		if (Root->U.PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", DIV);
		    RetVal = NULL;
		}
	    }
	    else
		RetVal = NULL;
	    break;
	case POWER:
	    if (IS_NUM_NODE(TempR) && IS_NUM_NODE(TempL)) {/* Numeric power. */
		Root->ObjType = NUMERIC_OBJ;
		Root->U.R = pow(TempL->U.R, TempR->U.R);
	    }
	    else if (IS_NUM_NODE(TempR) && IS_MAT_NODE(TempL)) {
		i = (int) TempR->U.R; /* Power MUST be integer in this case. */
		if (!APX_EQ(i, TempR->U.R) || i < -1) {
		    *IError = IE_ERR_MAT_POWER;
		    strcpy(CError, "^");
		    RetVal = NULL;
		}
		Root->ObjType = MATRIX_OBJ;
		Root->U.PObj = AllocObject("", MATRIX_OBJ, NULL);
		if (i == -1) {		     /* Generate the inverse matrix: */
		    if (!MatInverseMatrix(TempL->U.PObj->U.Mat,
					  Root->U.PObj->U.Mat)) {
			*IError = IE_ERR_MAT_POWER;
			strcpy(CError, "^");
			RetVal = NULL;
		    }
		}
		else {			      /* I must be positive integer. */
		    MatGenUnitMat(Root->U.PObj->U.Mat);
		    while (i--) MatMultTwo4by4(Root->U.PObj->U.Mat,
					       Root->U.PObj->U.Mat,
					       TempL->U.PObj->U.Mat);
		}
	    }
	    else if ((IS_POLY_NODE(TempR) || IS_SRF_NODE(TempR)) &&
		     (IS_POLY_NODE(TempL) || IS_SRF_NODE(TempL))) {
		TempLObj = ConvSrfToPolys(TempL);
		TempRObj = ConvSrfToPolys(TempR);
		Root->ObjType = POLY_OBJ;
		Root->U.PObj = BooleanMERGE(TempLObj, TempRObj);
		if (Root->U.PObj == NULL) {
		    IPGlblEvalError = IE_ERR_BOOLEAN_ERR;
		    UpdateCharError("Operator ", MINUS);
		    RetVal = NULL;
		}
	    }
	    else
		RetVal = NULL;
	    break;
	case UNARMINUS:
	    if (IS_NUM_NODE(TempR)) {
		Root->ObjType = NUMERIC_OBJ;
		Root->U.R = -TempR->U.R;
	    }
	    else if (IS_VEC_NODE(TempR)) {
		Root->ObjType = VECTOR_OBJ;
		Root->U.PObj = AllocObject("", VECTOR_OBJ, NULL);
		PT_COPY(Root->U.PObj->U.Vec, TempR->U.PObj->U.Vec);
		PT_SCALE(Root->U.PObj->U.Vec, -1.0);
	    }
	    else if (IS_MAT_NODE(TempR)) {
		Root->ObjType = MATRIX_OBJ;
		Root->U.PObj = AllocObject("", MATRIX_OBJ, NULL);
		R = -1.0;
		MatScale4by4(Root->U.PObj->U.Mat, TempR->U.PObj->U.Mat, &R);
	    }
	    else if (IS_POLY_NODE(TempR)) {
		Root->ObjType = POLY_OBJ;
		Root->U.PObj = BooleanNEG(TempR -> U.PObj);
	    }
	    else if (IS_CRV_NODE(TempR)) {
		Root->ObjType = CURVE_OBJ;
		Root->U.PObj = CurveReverse(TempR -> U.PObj);
	    }
	    else if (IS_SRF_NODE(TempR)) {
		Root->ObjType = SURFACE_OBJ;
		Root->U.PObj = SurfaceReverse(TempR -> U.PObj);
	    }
	    else
		RetVal = NULL;
	    break;
    }
    if (RetVal == NULL && *IError == IPE_NO_ERR) { /* Put general error msg: */
	*IError = IE_ERR_TYPE_MISMATCH;
	switch (Root->NodeKind) {
	    case PLUS:
		strcpy(CError, "Operator +");
		break;
	    case MINUS:
		strcpy(CError, "Operator -");
		break;
	    case MULT:
		strcpy(CError, "Operator *");
		break;
	    case DIV:
		strcpy(CError, "Operator /");
		break;
	    case POWER:
		strcpy(CError, "Operator ^");
		break;
	    case UNARMINUS:
		strcpy(CError, "Operator (unary) -");
		break;
	}
    }

    return RetVal;
}

/*****************************************************************************
*   If given object is a surface, its polygonal representation object is     *
* returned instead. Otherwise the given pointer is returned as is.           *
*****************************************************************************/
static ObjectStruct *ConvSrfToPolys(ParseTree *Srf)
{
    if (!IS_SRF_NODE(Srf)) return Srf -> U.PObj;

    if (Srf -> U.PObj -> U.Srf.Polygons == NULL)
	ComputeSurfacePolygons(Srf -> U.PObj);

    return Srf -> U.PObj -> U.Srf.Polygons;
}
[ RETURN TO DIRECTORY ]