/***************************************************************************** * "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 #endif /* __MSDOS__ */ #include #include #include #include #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; }