/***************************************************************************** * "Irit" - the 3d polygonal solid modeller. * * * * Written by: Gershon Elber Ver 0.2, Mar. 1990 * ****************************************************************************** * Module to provide the required interfact for the cagd library for the * * free form surfaces and curves. * *****************************************************************************/ #include #include #include "program.h" #include "allocate.h" #include "attribut.h" #include "objects.h" #include "primitiv.h" #include "windows.h" #include "freeform.h" #include "graphgen.h" static void ConvertCtlPt(ObjectStruct *PObjPt, CagdCtlPtStruct *CagdPt); static ObjectStruct *GetControlMesh(ObjectStruct *LstObjList, int UOrder, int VOrder, CagdGeomType GType, char **ErrStr); static ObjectStruct *GetControlPoly(ObjectStruct *PtObjList, int Order, CagdGeomType GType, char **ErrStr); static CagdRType *GetKnotVector(ObjectStruct *KntObjList, int Order, CagdRType *KnotVector, int *Length, char **ErrStr); static PolygonStruct *CagdPolys2IritPolys(CagdPolylineStruct *CagdPolys); /***************************************************************************** * Conver control point from IRIT to CAGD format. * *****************************************************************************/ static void ConvertCtlPt(ObjectStruct *PObjPt, CagdCtlPtStruct *CagdPt) { int i; CagdPointType PtType = PObjPt -> U.CtlPt.PtType; int PtSize = CAGD_IS_RATIONAL_PT(PtType) + CAGD_NUM_OF_PT_COORD(PtType); CagdRType *v = PObjPt -> U.CtlPt.Coords; CagdPt -> PtType = PtType; if (CAGD_IS_RATIONAL_PT(PtType)) for (i = 0; i < PtSize; i++) CagdPt -> Coords[i] = *v++; else for (i = 1; i <= PtSize; i++) CagdPt -> Coords[i] = *++v; } /***************************************************************************** * Routine to fetch the boolean object DrawCtlPt. * *****************************************************************************/ int GetDrawCtlPt(void) { int DrawCtlPt; ObjectStruct *PObj = GetObject("DRAWCTLPT"); if (PObj == NULL || !IS_NUM_OBJ(PObj)) { WndwInputWindowPutStr("No numeric object name DRAWCTLPT is defined"); DrawCtlPt = 0; } else DrawCtlPt = REAL_TO_INT(PObj -> U.R); return DrawCtlPt; } /***************************************************************************** * Routine to fetch the boolean object DrawCtlPt. * *****************************************************************************/ int GetFourPerFlat(void) { int FourPerFlat; ObjectStruct *PObj = GetObject("FLAT4PLY"); if (PObj == NULL || !IS_NUM_OBJ(PObj)) { WndwInputWindowPutStr("No numeric object name FLAT4PLY is defined"); FourPerFlat = 0; } else FourPerFlat = REAL_TO_INT(PObj -> U.R); return FourPerFlat; } /***************************************************************************** * Routine to copy the control mesh lists to the surface control mesh. * * The surface is allocated here as well. * * Returns the surface if o.k., otherwise NULL. * *****************************************************************************/ static ObjectStruct *GetControlMesh(ObjectStruct *LstObjList, int UOrder, int VOrder, CagdGeomType GType, char **ErrStr) { int i, j, k, PtSize, NumVertices, NumVerticesFirst = -1, NumLists = 0; CagdRType **r; RealType *v; ObjectStruct *SrfObj, *LstObj, *PtObj; CagdPointType PtType = CAGD_PT_E3_TYPE; if (!IS_OLST_OBJ(LstObjList)) FatalError("SURFACE: Not object list object!"); while ((LstObj = LstObjList -> U.PObjList[NumLists]) != NULL && NumLists < MAX_OBJ_LIST) { if (!IS_OLST_OBJ(LstObj)) { *ErrStr = "None list object found in list"; return NULL; } NumVertices = 0; while ((PtObj = LstObj -> U.PObjList[NumVertices]) != NULL && NumVertices < MAX_OBJ_LIST) { if (!IS_CTLPT_OBJ(PtObj)) { *ErrStr = "None point object found in list"; return NULL; } if (NumVertices++ == 0 && NumLists == 0) /* First one. */ PtType = PtObj -> U.CtlPt.PtType; else if (PtType != PtObj -> U.CtlPt.PtType) { *ErrStr = "Different point types found in list"; return NULL; } } if (NumLists++ == 0) NumVerticesFirst = NumVertices; else if (NumVerticesFirst != NumVertices) { *ErrStr = "Different size of point lists"; return NULL; } } if (NumVertices < 2 || NumLists < 2) { *ErrStr = "Less than 2 points in a row/col"; return NULL; } SrfObj = GenSrfObject("", NULL, NULL); switch (GType) { case CAGD_SBEZIER_TYPE: SrfObj -> U.Srf.Srf = BzrSrfNew(NumVertices, NumLists, PtType); break; case CAGD_SBSPLINE_TYPE: SrfObj -> U.Srf.Srf = BspSrfNew(NumVertices, NumLists, UOrder, VOrder, PtType); break; } SetObjectColor(SrfObj, GlblPrimColor); /* Set its default color. */ PtSize = CAGD_IS_RATIONAL_PT(PtType) + CAGD_NUM_OF_PT_COORD(PtType); for (r = SrfObj -> U.Srf.Srf -> Points, i = 0; i < NumLists; i++) { LstObj = LstObjList -> U.PObjList[i]; for (j = 0; j < NumVertices; j++) { v = LstObj -> U.PObjList[j] -> U.CtlPt.Coords; if (CAGD_IS_RATIONAL_PT(PtType)) for (k = 0; k < PtSize; k++) r[k][i * NumVertices + j] = *v++; else for (k = 1; k <= PtSize; k++) r[k][i * NumVertices + j] = *++v; } } return SrfObj; } /***************************************************************************** * Routine to copy the control polygon list to the curve control polygon. * * The curve is allocated here as well. * * Returns the curve if o.k., otherwise NULL. * *****************************************************************************/ static ObjectStruct *GetControlPoly(ObjectStruct *PtObjList, int Order, CagdGeomType GType, char **ErrStr) { int i, j, PtSize, NumVertices = 0; CagdRType **r; RealType *v; ObjectStruct *CrvObj, *PtObj; CagdPointType PtType = CAGD_PT_E3_TYPE; *ErrStr = NULL; if (!IS_OLST_OBJ(PtObjList)) FatalError("CURVE: Not object list object!"); while ((PtObj = PtObjList -> U.PObjList[NumVertices]) != NULL && NumVertices < MAX_OBJ_LIST) { if (!IS_CTLPT_OBJ(PtObj)) { *ErrStr = "None point object found in list"; return NULL; } if (NumVertices++ == 0) /* First one. */ PtType = PtObj -> U.CtlPt.PtType; else if (PtType != PtObj -> U.CtlPt.PtType) { *ErrStr = "Different point types found in list"; return NULL; } } if (NumVertices < 2) { *ErrStr = "Less than 2 points"; return NULL; } CrvObj = AllocObject("", CURVE_OBJ, NULL); switch (GType) { case CAGD_CBEZIER_TYPE: CrvObj -> U.Crv.Crv = BzrCrvNew(NumVertices, PtType); break; case CAGD_CBSPLINE_TYPE: CrvObj -> U.Crv.Crv = BspCrvNew(NumVertices, Order, PtType); break; } SetObjectColor(CrvObj, GlblPrimColor); /* Set its default color. */ PtSize = CAGD_IS_RATIONAL_PT(PtType) + CAGD_NUM_OF_PT_COORD(PtType); for (r = CrvObj -> U.Crv.Crv -> Points,i = 0; i < NumVertices; i++) { v = PtObjList -> U.PObjList[i] -> U.CtlPt.Coords; if (CAGD_IS_RATIONAL_PT(PtType)) for (j = 0; j < PtSize; j++) r[j][i] = *v++; else for (j = 1; j <= PtSize; j++) r[j][i] = *++v; } return CrvObj; } /***************************************************************************** * Routine to copy the list of knots into the knot vector provided. * * Returns KnotVector if o.k., NULL otherwise (sets ErrStr to description). * * If Length == 0 it is figured from the parameters and KnotVector is * * allocated here. * *****************************************************************************/ static CagdRType *GetKnotVector(ObjectStruct *KntObjList, int Order, CagdRType *KnotVector, int *Length, char **ErrStr) { int NumKnots = 0, NewKnotVector = FALSE; ObjectStruct *KntObj; *ErrStr = NULL; if (!IS_OLST_OBJ(KntObjList)) FatalError("KNOT: Not object list object!"); if (*Length == 0) { while ((KntObj = KntObjList -> U.PObjList[*Length]) != NULL && *Length < MAX_OBJ_LIST) (*Length)++; KnotVector = (CagdRType *) MyMalloc(sizeof(CagdRType) * *Length, ALLOC_OTHER); NewKnotVector = TRUE; } while ((KntObj = KntObjList -> U.PObjList[NumKnots]) != NULL && NumKnots < MAX_OBJ_LIST && NumKnots < *Length) { if (!IS_NUM_OBJ(KntObj)) { *ErrStr = "None numeric object found in list"; return NULL; } KnotVector[NumKnots++] = KntObj->U.R; } if (NumKnots == 1 && KnotVector[0] < KV_MIN_LEGAL) { switch ((int) (KnotVector[0] - 0.5)) { case KV_UNIFORM_OPEN: if (NewKnotVector) { MyFree((char *) KnotVector, ALLOC_OTHER); KnotVector = BspKnotUniformOpen(*Length - Order, Order, NULL); } else BspKnotUniformOpen(*Length - Order, Order, KnotVector); break; case KV_UNIFORM_FLOAT: if (NewKnotVector) { MyFree((char *) KnotVector, ALLOC_OTHER); KnotVector = BspKnotUniformFloat(*Length - Order, Order, NULL); } else BspKnotUniformFloat(*Length - Order, Order, KnotVector); break; default: *ErrStr = "Invalid knot value"; fprintf(stderr,"Knot = %10.6lg (%d)", KnotVector[0], (int) (KnotVector[0] - 0.5)); return NULL; } } else if (NumKnots != *Length) { *ErrStr = "Wrong knot vector length"; return NULL; } return KnotVector; } /***************************************************************************** * Routine to create a Bezier surface geometric object defined by a list of * * lists of vertices. * *****************************************************************************/ ObjectStruct *GenBezierSurfaceObject(ObjectStruct *LstObjList) { char *ErrStr, Line[LINE_LEN]; ObjectStruct *SrfObj = GetControlMesh(LstObjList, -1, -1, CAGD_SBEZIER_TYPE, &ErrStr); if (SrfObj == NULL) { sprintf(Line, "SBEZIER: %s, empty object result.\n", ErrStr); WndwInputWindowPutStr(Line); } return SrfObj; } /***************************************************************************** * Routine to create a Bezier curve geometric object defined by a list of * * vertices. * *****************************************************************************/ ObjectStruct *GenBezierCurveObject(ObjectStruct *PtObjList) { char *ErrStr, Line[LINE_LEN]; ObjectStruct *CrvObj = GetControlPoly(PtObjList, -1, CAGD_CBEZIER_TYPE, &ErrStr); if (CrvObj == NULL) { sprintf(Line, "CBEZIER: %s\n, empty object result.", ErrStr); WndwInputWindowPutStr(Line); } return CrvObj; } /***************************************************************************** * Routine to create a Bspline surface geometric object defined by a list * * of vertices. * *****************************************************************************/ ObjectStruct *GenBsplineSurfaceObject(RealType *RUOrder, RealType *RVOrder, ObjectStruct *LstObjList, ObjectStruct *KntObjList) { int Len1, Len2, UOrder = REAL_PTR_TO_INT(RUOrder), VOrder = REAL_PTR_TO_INT(RVOrder); char *ErrStr, Line[LINE_LEN]; ObjectStruct *SrfObj = GetControlMesh(LstObjList, UOrder, VOrder, CAGD_SBSPLINE_TYPE, &ErrStr); if (SrfObj == NULL) { sprintf(Line, "SBSPLINE: %s, empty object result.\n", ErrStr); WndwInputWindowPutStr(Line); return NULL; } if (KntObjList -> U.PObjList[0] == NULL || KntObjList -> U.PObjList[1] == NULL || KntObjList -> U.PObjList[2] != NULL) { WndwInputWindowPutStr("SBSPLINE: Exactly two knot vectors expected"); MyFree((char *) SrfObj, ALLOC_OBJECT); return NULL; } Len1 = SrfObj->U.Srf.Srf->ULength + UOrder; Len2 = SrfObj->U.Srf.Srf->VLength + VOrder; if (!GetKnotVector(KntObjList -> U.PObjList[0], UOrder, SrfObj->U.Srf.Srf->UKnotVector, &Len1, &ErrStr) || !GetKnotVector(KntObjList -> U.PObjList[1], VOrder, SrfObj->U.Srf.Srf->VKnotVector, &Len2, &ErrStr)) { sprintf(Line, "SBSPLINE: %s, empty object result.\n", ErrStr); WndwInputWindowPutStr(Line); MyFree((char *) SrfObj, ALLOC_OBJECT); return NULL; } return SrfObj; } /***************************************************************************** * Routine to create a Bspline curve geometric object defined by a list of * * vertices. * *****************************************************************************/ ObjectStruct *GenBsplineCurveObject(RealType *ROrder, ObjectStruct *PtObjList, ObjectStruct *KntObjList) { int Len, Order = REAL_PTR_TO_INT(ROrder); char *ErrStr, Line[LINE_LEN]; ObjectStruct *CrvObj = GetControlPoly(PtObjList, Order, CAGD_CBSPLINE_TYPE, &ErrStr); if (CrvObj == NULL) { sprintf(Line, "CBSPLINE: %s, empty object result.\n", ErrStr); WndwInputWindowPutStr(Line); return NULL; } if (!IS_OLST_OBJ(KntObjList)) FatalError("CBSPLINE: Knots is not object list object!"); Len = CrvObj->U.Crv.Crv->Length + Order; if (!GetKnotVector(KntObjList, Order, CrvObj->U.Crv.Crv->KnotVector, &Len, &ErrStr)) { sprintf(Line, "CBSPLINE: %s, empty object result.\n", ErrStr); WndwInputWindowPutStr(Line); MyFree((char *) CrvObj, ALLOC_OBJECT); return NULL; } return CrvObj; } /***************************************************************************** * Routine to subdivide a surface into two in specified direction (1 or 2) * * and specified parameter value. * *****************************************************************************/ ObjectStruct *DivideSurfaceObject(ObjectStruct *SrfObj, RealType *RDir, RealType *ParamVal) { int Dir = REAL_PTR_TO_INT(RDir); CagdSrfStruct *Srf = CagdSrfSubdivAtParam(SrfObj -> U.Srf.Srf, *ParamVal, Dir); ObjectStruct *Srf1, *Srf2, *SrfList; if (Srf == NULL) return NULL; Srf1 = GenSrfObject("", Srf, NULL), SetObjectColor(Srf1, GetObjectColor(SrfObj)); Srf2 = GenSrfObject("", Srf->Pnext, NULL), SetObjectColor(Srf2, GetObjectColor(SrfObj)); Srf -> Pnext = NULL; SrfList = AllocObject("", OBJ_LIST_OBJ, NULL); SrfList -> U.PObjList[0] = Srf1; SrfList -> U.PObjList[1] = Srf2; SrfList -> U.PObjList[2] = NULL; return SrfList; } /***************************************************************************** * Routine to extract a surface region in specified direction (1 or 2) and * * specified parameter values. * *****************************************************************************/ ObjectStruct *RegionFromSurfaceObject(ObjectStruct *SrfObj, RealType *RDir, RealType *ParamVal1, RealType *ParamVal2) { int Dir = REAL_PTR_TO_INT(RDir); CagdSrfStruct *Srf = CagdSrfRegionFromSrf(SrfObj -> U.Srf.Srf, *ParamVal1, *ParamVal2, Dir); if (Srf == NULL) return NULL; SrfObj = GenSrfObject("", Srf, NULL); return SrfObj; } /***************************************************************************** * Routine to subdivide a curve into two in specified parameter value. * *****************************************************************************/ ObjectStruct *DivideCurveObject(ObjectStruct *CrvObj, RealType *ParamVal) { CagdCrvStruct *Crv = CagdCrvSubdivAtParam(CrvObj -> U.Crv.Crv, *ParamVal); ObjectStruct *Crv1, *Crv2, *CrvList; if (Crv == NULL) return NULL; Crv1 = GenCrvObject("", Crv, NULL), SetObjectColor(Crv1, GetObjectColor(CrvObj)); Crv2 = GenCrvObject("", Crv->Pnext, NULL), SetObjectColor(Crv2, GetObjectColor(CrvObj)); Crv -> Pnext = NULL; CrvList = AllocObject("", OBJ_LIST_OBJ, NULL); CrvList -> U.PObjList[0] = Crv1; CrvList -> U.PObjList[1] = Crv2; CrvList -> U.PObjList[2] = NULL; return CrvList; } /***************************************************************************** * Routine to extract a curve region in specified parameter values. * *****************************************************************************/ ObjectStruct *RegionFromCurveObject(ObjectStruct *CrvObj, RealType *ParamVal1, RealType *ParamVal2) { CagdCrvStruct *Crv = CagdCrvRegionFromCrv(CrvObj -> U.Crv.Crv, *ParamVal1, *ParamVal2); if (Crv == NULL) return NULL; CrvObj = GenCrvObject("", Crv, NULL); return CrvObj; } /***************************************************************************** * Routine to refine surface in specified direction (1 or 2) and knot vector. * * If, however, Replace is non zero, KnotsObj REPLACES current vector. * *****************************************************************************/ ObjectStruct *RefineSurfaceObject(ObjectStruct *SrfObj, RealType *RDir, RealType *RReplace, ObjectStruct *KnotsObj) { int n = 0, Replace = REAL_PTR_TO_INT(RReplace), Dir = REAL_PTR_TO_INT(RDir); char *ErrStr, Line[LINE_LEN]; CagdRType *t = GetKnotVector(KnotsObj, 0, NULL, &n, &ErrStr); CagdSrfStruct *RefSrf; ObjectStruct *RefSrfObj; if (t == NULL) { sprintf(Line, "REFINE: %s, empty object result.\n", ErrStr); WndwInputWindowPutStr(Line); MyFree((char *) SrfObj, ALLOC_OBJECT); return NULL; } RefSrf = CagdSrfRefineAtParams(SrfObj -> U.Srf.Srf, Dir, Replace, t, n); MyFree((char *) t, ALLOC_OTHER); if (RefSrf == NULL) return NULL; RefSrfObj = GenSrfObject("", RefSrf, NULL), SetObjectColor(RefSrfObj, GetObjectColor(SrfObj)); return RefSrfObj; } /***************************************************************************** * Routine to refine curve in specified knot vector. * * If, however, Replace is non zero, knotsObj REPLACES current vector. * *****************************************************************************/ ObjectStruct *RefineCurveObject(ObjectStruct *CrvObj, RealType *RReplace, ObjectStruct *KnotsObj) { int n = 0, Replace = REAL_PTR_TO_INT(RReplace); char *ErrStr, Line[LINE_LEN]; CagdRType *t = GetKnotVector(KnotsObj, 0, NULL, &n, &ErrStr); CagdCrvStruct *RefCrv; ObjectStruct *RefCrvObj; if (t == NULL) { sprintf(Line, "REFINE: %s, empty object result.\n", ErrStr); WndwInputWindowPutStr(Line); MyFree((char *) CrvObj, ALLOC_OBJECT); return NULL; } RefCrv = CagdCrvRefineAtParams(CrvObj -> U.Crv.Crv, Replace, t, n); MyFree((char *) t, ALLOC_OTHER); if (RefCrv == NULL) return NULL; RefCrvObj = GenCrvObject("", RefCrv, NULL), SetObjectColor(RefCrvObj, GetObjectColor(CrvObj)); return RefCrvObj; } /***************************************************************************** * Routine to evaluate surface in specified parameter values. * *****************************************************************************/ ObjectStruct *EvalSurfaceObject(ObjectStruct *SrfObj, RealType *u, RealType *v) { CagdRType *Pt = CagdSrfEval(SrfObj -> U.Srf.Srf, *u, *v); ObjectStruct *CtlPtObj = GenCtlPtObject("", SrfObj -> U.Srf.Srf -> PType, Pt, NULL, NULL); return CtlPtObj; } /***************************************************************************** * Routine to evaluate curve in specified parameter value. * *****************************************************************************/ ObjectStruct *EvalCurveObject(ObjectStruct *CrvObj, RealType *t) { CagdRType *Pt = CagdCrvEval(CrvObj -> U.Crv.Crv, *t); ObjectStruct *CtlPtObj = GenCtlPtObject("", CrvObj -> U.Crv.Crv -> PType, Pt, NULL, NULL); return CtlPtObj; } /***************************************************************************** * Routine to evaluate surface normal in specified parameter values. * *****************************************************************************/ ObjectStruct *NormalSurfaceObject(ObjectStruct *SrfObj, RealType *u, RealType *v) { int i; RealType V[3]; CagdVecStruct *Vec = CagdSrfNormal(SrfObj -> U.Srf.Srf, *u, *v); ObjectStruct *NormalObj; for (i = 0; i < 3; i++) V[i] = Vec -> Vec[i]; NormalObj = GenVecObject("", &V[0], &V[1], &V[2], NULL); return NormalObj; } /***************************************************************************** * Routine to evaluate surface tangent in specified parameter value and dir.. * *****************************************************************************/ ObjectStruct *TangentSurfaceObject(ObjectStruct *SrfObj, RealType *RDir, RealType *u, RealType *v) { int i, Dir = REAL_PTR_TO_INT(RDir); RealType V[3]; CagdVecStruct *Vec = CagdSrfTangent(SrfObj -> U.Srf.Srf, *u, *v, Dir); ObjectStruct *TangentObj; for (i = 0; i < 3; i++) V[i] = Vec -> Vec[i]; TangentObj = GenVecObject("", &V[0], &V[1], &V[2], NULL); return TangentObj; } /***************************************************************************** * Routine to evaluate curve in specified parameter value. * *****************************************************************************/ ObjectStruct *TangentCurveObject(ObjectStruct *CrvObj, RealType *t) { int i; RealType V[3]; CagdVecStruct *Vec = CagdCrvTangent(CrvObj -> U.Crv.Crv, *t); ObjectStruct *TangentObj; for (i = 0; i < 3; i++) V[i] = Vec -> Vec[i]; TangentObj = GenVecObject("", &V[0], &V[1], &V[2], NULL); return TangentObj; } /***************************************************************************** * Routine to extract an isoparametric curve out of a surface. * *****************************************************************************/ ObjectStruct *CurveFromSurface(ObjectStruct *SrfObj, RealType *RDir, RealType *ParamVal) { int Dir = REAL_PTR_TO_INT(RDir); CagdCrvStruct *Crv = CagdCrvFromSrf(SrfObj -> U.Srf.Srf, *ParamVal, Dir); ObjectStruct *CrvObj; if (Crv == NULL) return NULL; CrvObj = GenCrvObject("", Crv, NULL); return CrvObj; } /***************************************************************************** * Routine to extract an isoparametric curve out of a surface mesh. * *****************************************************************************/ ObjectStruct *CurveFromSrfMesh(ObjectStruct *SrfObj, RealType *RDir, RealType *RIndex) { int Dir = REAL_PTR_TO_INT(RDir), Index = REAL_PTR_TO_INT(RIndex); CagdCrvStruct *Crv = CagdCrvFromMesh(SrfObj -> U.Srf.Srf, Index, Dir); ObjectStruct *CrvObj; if (Crv == NULL) return NULL; CrvObj = GenCrvObject("", Crv, NULL); return CrvObj; } /***************************************************************************** * Routine to reverse a curve. * *****************************************************************************/ ObjectStruct *CurveReverse(ObjectStruct *CrvObj) { CagdCrvStruct *RevCrv = CagdCrvReverse(CrvObj -> U.Crv.Crv); if (RevCrv == NULL) return NULL; CrvObj = GenCrvObject("", RevCrv, NULL); return CrvObj; } /***************************************************************************** * Routine to reverse a surface. * *****************************************************************************/ ObjectStruct *SurfaceReverse(ObjectStruct *SrfObj) { CagdSrfStruct *RevSrf = CagdSrfReverse(SrfObj -> U.Srf.Srf); if (RevSrf == NULL) return NULL; SrfObj = GenSrfObject("", RevSrf, NULL); return SrfObj; } /***************************************************************************** * Routine to convert a curve to a piecewise linear polyline approximation * * and convert its control polygon into polyline as well. * * Result is saved in the PLPolys/CtlPoly curve slots. * * If however approximation alread exists, no computation is performed. * *****************************************************************************/ void ComputeCurveIsoLines(ObjectStruct *PObj) { int i, j, DrawCtlPtColor = GetDrawCtlPt(), Resolution = GetResolution(TRUE), RealResolution = GetResolution(FALSE); if (!IS_CRV_OBJ(PObj)) FatalError("Curve was expected."); if (RealResolution > 0 && PObj -> U.Crv.PLPolys == NULL) { for (i = 1, j = Resolution; j > 0 && i < 10; i++, j >>= 1); BzrCrvSetCache(i, TRUE); PObj -> U.Crv.PLPolys = CagdCrv2Polyline(PObj -> U.Crv.Crv, i); } if (DrawCtlPtColor && PObj -> U.Crv.CtlPoly == NULL) { PObj -> U.Crv.CtlPoly = CagdCrv2CtrlPoly(PObj -> U.Crv.Crv); } } /***************************************************************************** * Routine to convert a surface to a set of piecewise linear polylines * * approximation and convert its control mesh into set of polyline as well. * * Result is saved in the PLPolys/CtlMsh surface slots. * * If however approximation alread exists, no computation is performed. * *****************************************************************************/ void ComputeSurfaceIsoLines(ObjectStruct *PObj) { int i, j, DrawCtlPtColor = GetDrawCtlPt(), Resolution = GetResolution(TRUE), RealResolution = GetResolution(FALSE); if (!IS_SRF_OBJ(PObj)) FatalError("Surface was expected."); if (RealResolution > 0 && PObj -> U.Srf.PLPolys == NULL) { for (i = 1, j = Resolution; j > 0 && i < 10; i++, j >>= 1); BzrCrvSetCache(i, TRUE); PObj -> U.Srf.PLPolys = CagdSrf2Polylines(PObj -> U.Srf.Srf, Resolution, i); } if (DrawCtlPtColor && PObj -> U.Srf.CtlMesh == NULL) { PObj -> U.Srf.CtlMesh = CagdSrf2CtrlMesh(PObj -> U.Srf.Srf); } } /***************************************************************************** * Routine to convert a surface to a set of polygons approximating it. * * Result is saved in the Polygons surface slot. * * If however approximation alread exists, no computation is performed. * *****************************************************************************/ void ComputeSurfacePolygons(ObjectStruct *PObj) { int i, j, Resolution = GetResolution(TRUE), FourPerFlat = GetFourPerFlat(); char *SrfStrResolution = GetObjectStrAttrib(PObj, "resolution"); VectorType Vin; VertexStruct *V; PolygonStruct *P, *PHead = NULL; CagdPolygonStruct *CagdPoly, *CagdPolys; if (PObj -> U.Srf.Polygons != NULL) return; if (SrfStrResolution) { float SrfRelResolution; if (sscanf(SrfStrResolution, "%f", &SrfRelResolution) == 1) { Resolution = REAL_TO_INT(Resolution * SrfRelResolution); } } #ifndef __MSDOS__ /* Make the resolution more reasonable (very slow on MSDOS). */ Resolution *= 2; #endif /* __MSDOS__ */ if (GetObjectStrAttrib(PObj, "twoperflat") != NULL) FourPerFlat = FALSE; if (GetObjectStrAttrib(PObj, "fourperflat") != NULL) FourPerFlat = TRUE; CagdPolys = CagdSrf2Polygons(PObj -> U.Srf.Srf, Resolution, TRUE, FourPerFlat); for (CagdPoly = CagdPolys; CagdPoly != NULL; CagdPoly = CagdPoly -> Pnext) { /* All polygons are triangles! */ P = AllocPolygon(0, 0, V = AllocVertex(0, 0, NULL, NULL), NULL); V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; V -> Pnext = P -> V; /* Make the Vertex list circular. */ SET_CONVEX_POLY(P); /* Mark it as convex polygon. */ for (i = 0; i < 3; i++) { /* Convert to vertices. */ V = V -> Pnext; for (j = 0; j < 3; j++) /* Convert to our format. */ V -> Pt[j] = CagdPoly -> Polygon[i].Pt[j]; for (j = 0; j < 3; j++) V -> Normal[j] = CagdPoly -> Normal[i].Vec[j]; } PT_ADD(Vin, CagdPoly -> Polygon[0].Pt, CagdPoly -> Normal[0].Vec); UpdatePolyPlane(P, Vin); /* Update plane equation. */ P -> Pnext = PHead; PHead = P; } CagdPolygonFreeList(CagdPolys); PObj -> U.Srf.Polygons = GenPolyObject("", PHead, NULL); SetObjectColor(PObj -> U.Srf.Polygons, GlblPrimColor); } /***************************************************************************** * Routine to convert a surface/list of surfaces into set of polygons. * *****************************************************************************/ ObjectStruct *Geometry2Polygons(ObjectStruct *Obj) { ObjectStruct *PObj; if (IS_SRF_OBJ(Obj)) { ComputeSurfacePolygons(Obj); PObj = CopyObject(NULL, Obj -> U.Srf.Polygons, FALSE); SetObjectColor(PObj, GlblPrimColor); /* Set its default color. */ return PObj; } else if (IS_OLST_OBJ(Obj)) { int i = 0; PolygonStruct *P; ObjectStruct *PObjAll = NULL; while ((PObj = Obj -> U.PObjList[i++]) != NULL && i < MAX_OBJ_LIST) { PObj = Geometry2Polygons(PObj); if (PObjAll) { if (PObj -> U.Pl.P) { for (P = PObj -> U.Pl.P; P -> Pnext != NULL; P = P -> Pnext); P -> Pnext = PObjAll -> U.Pl.P; PObjAll -> U.Pl.P = PObj -> U.Pl.P; PObj -> U.Pl.P = NULL; } MyFree((char *) PObj, ALLOC_OBJECT); } else { PObjAll = PObj; } } return PObjAll; } else { WndwInputWindowPutStr("Unconvertable to polygons object ignored"); return NULL; } } /***************************************************************************** * Routine to convert Cagd lib polylines to Irit polylines. * *****************************************************************************/ static PolygonStruct *CagdPolys2IritPolys(CagdPolylineStruct *CagdPolys) { CagdPolylineStruct *CagdPoly; PolygonStruct *PHead = NULL; for (CagdPoly = CagdPolys; CagdPoly != NULL; CagdPoly = CagdPoly -> Pnext) { int i, j; VertexStruct *V; PolygonStruct *P; P = AllocPolygon(0, 0, V = AllocVertex(0, 0, NULL, NULL), NULL); for (i = 0; i < CagdPoly -> Length; i++) { /* Convert to vertices. */ for (j = 0; j < 3; j++) /* Convert to our format. */ V -> Pt[j] = CagdPoly -> Polyline[i].Pt[j]; if (i < CagdPoly -> Length - 1) { V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext; } } P -> Pnext = PHead; PHead = P; } return PHead; } /***************************************************************************** * Routine to convert a surface/curve/list of them into set of polylines. * *****************************************************************************/ ObjectStruct *Geometry2Polylines(ObjectStruct *Obj) { ObjectStruct *PObj; PolygonStruct *P, *PTail, *PHead; int DoMeshes = GetDrawCtlPt(); if (IS_SRF_OBJ(Obj)) { ComputeSurfaceIsoLines(Obj); if (Obj -> U.Srf.PLPolys != NULL) PHead = CagdPolys2IritPolys(Obj -> U.Srf.PLPolys); else PHead = NULL; if (DoMeshes && Obj -> U.Srf.CtlMesh != NULL) { P = CagdPolys2IritPolys(Obj -> U.Srf.CtlMesh); for (PTail = P; PTail -> Pnext != NULL; PTail = PTail -> Pnext); PTail -> Pnext = PHead; PHead = P; } PObj = GenPolyObject("", PHead, NULL); SetObjectColor(PObj, GlblPrimColor); /* Set its default color. */ SET_POLYLINE_OBJ(PObj); return PObj; } if (IS_CRV_OBJ(Obj)) { ComputeCurveIsoLines(Obj); if (Obj -> U.Crv.PLPolys != NULL) PHead = CagdPolys2IritPolys(Obj -> U.Srf.PLPolys); else PHead = NULL; if (DoMeshes && Obj -> U.Crv.CtlPoly != NULL) { P = CagdPolys2IritPolys(Obj -> U.Crv.CtlPoly); for (PTail = P; PTail -> Pnext != NULL; PTail = PTail -> Pnext); PTail -> Pnext = PHead; PHead = P; } PObj = GenPolyObject("", PHead, NULL); SetObjectColor(PObj, GlblPrimColor); /* Set its default color. */ SET_POLYLINE_OBJ(PObj); return PObj; } else if (IS_OLST_OBJ(Obj)) { int i = 0; ObjectStruct *PObjAll = NULL; while ((PObj = Obj -> U.PObjList[i++]) != NULL && i < MAX_OBJ_LIST) { PObj = Geometry2Polylines(PObj); if (PObjAll) { if (PObj -> U.Pl.P) { for (P = PObj -> U.Pl.P; P -> Pnext != NULL; P = P -> Pnext); P -> Pnext = PObjAll -> U.Pl.P; PObjAll -> U.Pl.P = PObj -> U.Pl.P; PObj -> U.Pl.P = NULL; } MyFree((char *) PObj, ALLOC_OBJECT); } else { PObjAll = PObj; } } return PObjAll; } else { WndwInputWindowPutStr("Unconvertable to polylines object ignored"); return NULL; } } /***************************************************************************** * Creates a circle on the XY plane. * *****************************************************************************/ ObjectStruct *GenCircleCurveObject(VectorType Position, RealType *Radius) { int i; CagdPtStruct Pos; CagdCrvStruct *CircCrv; ObjectStruct *CrvObj; for (i = 0; i < 3; i++) Pos.Pt[i] = Position[i]; CircCrv = BspCrvCreateCircle(&Pos, *Radius); if (CircCrv == NULL) return NULL; CrvObj = GenCrvObject("", CircCrv, NULL); return CrvObj; } /***************************************************************************** * Creates an arbitrary arc specified by Two end points and Center. Arc must * * be less than 180 degree. * *****************************************************************************/ ObjectStruct *GenArcCurveObject(VectorType Start, VectorType Center, VectorType End) { int i; CagdPtStruct StartPt, CenterPt, EndPt; CagdCrvStruct *ArcCrv; ObjectStruct *CrvObj; for (i = 0; i < 3; i++) { StartPt.Pt[i] = Start[i]; CenterPt.Pt[i] = Center[i]; EndPt.Pt[i] = End[i]; } ArcCrv = BzrCrvCreateArc(&StartPt, &CenterPt, &EndPt); if (ArcCrv == NULL) return NULL; CrvObj = GenCrvObject("", ArcCrv, NULL); return CrvObj; } /***************************************************************************** * Construct a ruled surface out of the two provided curves. The two curves * * must have same point type/curve type/order (and knot vector if Bspline). * *****************************************************************************/ ObjectStruct *GenRuledSrfObject(ObjectStruct *Crv1, ObjectStruct *Crv2) { ObjectStruct *SrfObj; CagdSrfStruct *RuledSrf = CagdRuledSrf(Crv1 -> U.Crv.Crv, Crv2 -> U.Crv.Crv, 2, 2); if (RuledSrf == NULL) return NULL; SrfObj = GenSrfObject("", RuledSrf, NULL); return SrfObj; } /***************************************************************************** * Construct a boolean sum surface out of the four provided curves. * *****************************************************************************/ ObjectStruct *GenBoolSumSrfObject(ObjectStruct *Crv1, ObjectStruct *Crv2, ObjectStruct *Crv3, ObjectStruct *Crv4) { ObjectStruct *SrfObj; CagdSrfStruct *BoolSumSrf = CagdBoolSumSrf(Crv1 -> U.Crv.Crv, Crv2 -> U.Crv.Crv, Crv3 -> U.Crv.Crv, Crv4 -> U.Crv.Crv); if (BoolSumSrf == NULL) return NULL; SrfObj = GenSrfObject("", BoolSumSrf, NULL); return SrfObj; } /***************************************************************************** * Construct a surface out of the provided curve list. * *****************************************************************************/ ObjectStruct *GenSrfFromCrvsObject(ObjectStruct *CrvList) { int i, NumCrvs = 0; ObjectStruct *SrfObj, *CrvObj; CagdSrfStruct *Srf; if (!IS_OLST_OBJ(CrvList)) FatalError("SURFACE: Not object list object!"); while ((CrvObj = CrvList -> U.PObjList[NumCrvs]) != NULL && NumCrvs < MAX_OBJ_LIST) { if (!IS_CRV_OBJ(CrvObj)) { WndwInputWindowPutStr("SURFACE: List contains non curve object(s)."); return NULL; } if (CrvObj -> U.Crv.Crv -> Pnext != NULL) { WndwInputWindowPutStr("SURFACE: nested curve lists are disallowed."); return NULL; } NumCrvs++; } /* Chain all curves into a single list and invoke the srf constructor: */ for (i = 0; i < NumCrvs; i++) CrvList -> U.PObjList[i] -> U.Crv.Crv -> Pnext = i < NumCrvs - 1 ? CrvList -> U.PObjList[i + 1] -> U.Crv.Crv : NULL; Srf = CagdSrfFromCrvs(CrvList -> U.PObjList[0] -> U.Crv.Crv); for (i = 0; i < NumCrvs; i++) CrvList -> U.PObjList[i] -> U.Crv.Crv -> Pnext = NULL; if (Srf == NULL) return NULL; SrfObj = GenSrfObject("", Srf, NULL); return SrfObj; } /***************************************************************************** * Construct a Sweep surface out of the CrossSection curve, Axis curve and * * optional Scaling curve and Scaler which scales the CrossSection. * *****************************************************************************/ ObjectStruct *GenSweepSrfObject(ObjectStruct *CrossSection, ObjectStruct *Axis, ObjectStruct *ScalingCrv, RealType *Scale) { ObjectStruct *SrfObj; CagdSrfStruct *SweepSrf = CagdSweepSrf(CrossSection -> U.Crv.Crv, Axis -> U.Crv.Crv, ScalingCrv ? ScalingCrv -> U.Crv.Crv : NULL, *Scale); if (SweepSrf == NULL) return NULL; SrfObj = GenSrfObject("", SweepSrf, NULL); return SrfObj; } /***************************************************************************** * Computes an approximation to the offset of a (planar) curve or a surface. * *****************************************************************************/ ObjectStruct *GenOffsetObject(ObjectStruct *Obj, RealType *Offset) { if (IS_SRF_OBJ(Obj)) { ObjectStruct *SrfObj; CagdSrfStruct *OffsetSrf = CagdSrfOffset(Obj -> U.Srf.Srf, *Offset); if (OffsetSrf == NULL) return NULL; SrfObj = GenSrfObject("", OffsetSrf, NULL); return SrfObj; } else if (IS_CRV_OBJ(Obj)) { ObjectStruct *CrvObj; CagdCrvStruct *OffsetCrv = CagdCrvOffset(Obj -> U.Crv.Crv, *Offset); if (OffsetCrv == NULL) return NULL; CrvObj = GenCrvObject("", OffsetCrv, NULL); return CrvObj; } else { WndwInputWindowPutStr("Offset allowed on curves/surfaces only"); return NULL; } } /***************************************************************************** * Merge two curves/ctl points into one curve by adding a linear segment * * between the first end point to second start point. * *****************************************************************************/ ObjectStruct *MergeCurvesAndCtlPoints(ObjectStruct *PObj1, ObjectStruct *PObj2) { ObjectStruct *CrvObj; CagdCrvStruct *Crv = NULL; CagdPtStruct Pt1, Pt2; if (IS_CRV_OBJ(PObj1)) { if (IS_CRV_OBJ(PObj2)) { Crv = CagdMergeCrvCrv(PObj1 -> U.Crv.Crv, PObj2 -> U.Crv.Crv); } else if (IS_CTLPT_OBJ(PObj2)) { CagdRType *Coords2 = PObj2 -> U.CtlPt.Coords; CagdCoerceToE3(Pt2.Pt, &Coords2, -1, PObj2 -> U.CtlPt.PtType); Crv = CagdMergeCrvPt(PObj1 -> U.Crv.Crv, &Pt2); } else FatalError("Curve/CtlPt was expected."); } else if (IS_CTLPT_OBJ(PObj1)) { CagdRType *Coords1 = PObj1 -> U.CtlPt.Coords; CagdCoerceToE3(Pt1.Pt, &Coords1, -1, PObj1 -> U.CtlPt.PtType); if (IS_CRV_OBJ(PObj2)) { Crv = CagdMergePtCrv(&Pt1, PObj2 -> U.Crv.Crv); } else if (IS_CTLPT_OBJ(PObj2)) { CagdRType *Coords2 = PObj2 -> U.CtlPt.Coords; CagdCoerceToE3(Pt2.Pt, &Coords2, -1, PObj2 -> U.CtlPt.PtType); Crv = CagdMergePtPt(&Pt1, &Pt2); } else FatalError("Curve/CtlPt was expected."); } else FatalError("Curve/CtlPt was expected."); if (Crv == NULL) return NULL; CrvObj = GenCrvObject("", Crv, NULL); return CrvObj; } /***************************************************************************** * Editing of a single control point of a curve. * *****************************************************************************/ ObjectStruct *EditCrvControlPoint(ObjectStruct *PObjCrv, ObjectStruct *PObjPt, RealType *Index) { ObjectStruct *CrvObj; CagdCtlPtStruct CagdCtlPt; CagdCrvStruct *Crv; ConvertCtlPt(PObjPt, &CagdCtlPt); Crv = CagdEditSingleCrvPt(PObjCrv -> U.Crv.Crv, &CagdCtlPt, REAL_PTR_TO_INT(Index)); CrvObj = GenCrvObject("", Crv, NULL); return CrvObj; } /***************************************************************************** * Editing of a single control point of a surface. * *****************************************************************************/ ObjectStruct *EditSrfControlPoint(ObjectStruct *PObjSrf, ObjectStruct *PObjPt, RealType *UIndex, RealType *VIndex) { ObjectStruct *SrfObj; CagdCtlPtStruct CagdCtlPt; CagdSrfStruct *Srf; ConvertCtlPt(PObjPt, &CagdCtlPt); Srf = CagdEditSingleSrfPt(PObjSrf -> U.Srf.Srf, &CagdCtlPt, REAL_PTR_TO_INT(UIndex), REAL_PTR_TO_INT(VIndex)); SrfObj = GenSrfObject("", Srf, NULL); return SrfObj; } /***************************************************************************** * Editing of a single control point of a curve. * *****************************************************************************/ ObjectStruct *RaiseCurveObject(ObjectStruct *PObjCrv, RealType *RNewOrder) { ObjectStruct *CrvObj; CagdCrvStruct *TCrv, *Crv = PObjCrv -> U.Crv.Crv; int OldOrder = Crv -> Order, NewOrder = REAL_PTR_TO_INT(RNewOrder); if (NewOrder <= OldOrder) { WndwInputWindowPutStr("Order to raise less the current"); return NULL; } while (OldOrder++ < NewOrder) { TCrv = CagdCrvDegreeRaise(Crv); if (Crv != PObjCrv -> U.Crv.Crv) CagdCrvFree(Crv); Crv = TCrv; } CrvObj = GenCrvObject("", Crv, NULL); return CrvObj; } /***************************************************************************** * Editing of a single control point of a curve. * *****************************************************************************/ ObjectStruct *RaiseSurfaceObject(ObjectStruct *PObjSrf, RealType *RDir, RealType *RNewOrder ) { ObjectStruct *SrfObj; CagdSrfStruct *TSrf, *Srf = PObjSrf -> U.Srf.Srf; int Dir = REAL_PTR_TO_INT(RDir), OldOrder = Dir == CAGD_CONST_U_DIR ? Srf -> VOrder : Srf -> UOrder, NewOrder = REAL_PTR_TO_INT(RNewOrder); if (NewOrder <= OldOrder) { WndwInputWindowPutStr("Order to raise less the current"); return NULL; } while (OldOrder++ < NewOrder) { TSrf = CagdSrfDegreeRaise(Srf, Dir); if (Srf != PObjSrf -> U.Srf.Srf) CagdSrfFree(Srf); Srf = TSrf; } SrfObj = GenSrfObject("", Srf, NULL); return SrfObj; }