home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * "Irit" - the 3d (not only polygonal) solid modeller. *
- * *
- * Written by: Gershon Elber Ver 0.2, Mar. 1990 *
- ******************************************************************************
- * Module to generate the geometric primitives defined in the system. The *
- * primitives currently defined are: *
- * 1. BOX - main planes parallel box. *
- * 2. GBOX - generalized box - 6 arbitrary planes. *
- * 3. CYLIN - cylinder with any main direction. *
- * 4. CONE, CONE2 - cone with any main direction (two bases). *
- * 5. SPHERE *
- * 6. TORUS - with any main direction. *
- * 7. PLANE - non closed, single polygon object: circle with resolution edges *
- * 8. POLY - directly define single polygon object by specifing its vertices. *
- * In addition, the following lower level operations are defined to create *
- * objects - EXTRUDE, and SURFREV, both require a polygon and a vector to *
- * extrude/rotate the polygon along. *
- *****************************************************************************/
-
- #include <stdio.h>
- #include <math.h>
- #include "irit_sm.h"
- #include "geomat3d.h"
- #include "allocate.h"
- #include "attribut.h"
- #include "convex.h"
- #include "primitiv.h"
-
- #define MIN_RESOLUTION 4
-
- static int GlblResolution = 16;
-
- static IPPolygonStruct *GenInsidePoly(IPPolygonStruct *Pl);
- static IPPolygonStruct *GenPolygon4Vrtx(VectorType V1,
- VectorType V2,
- VectorType V3,
- VectorType V4,
- VectorType Vin,
- IPPolygonStruct *Pnext);
- static IPPolygonStruct *GenPolygon3Vrtx(VectorType V1,
- VectorType V2,
- VectorType V3,
- VectorType Vin,
- IPPolygonStruct *Pnext);
- static void UpdateVertexNormal(NormalType Normal,
- PointType Pt,
- PointType InPt,
- int Perpendicular,
- PointType PerpPt);
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a BOX geometric object defined by Pt - the minimum V
- * 3d point, and Width - Dx Dy & Dz vector. 4 V
- * Order of vertices is as 5 7 V
- * follows in the picture: | 6 | V
- * | | | V
- * (Note vertex 0 is hidden behind edge 2-6) | | | V
- * 1 | 3 V
- * 2 V
- * All dimensions can be negative, denoting the reversed direction. M
- * *
- * PARAMETERS: M
- * Pt: Low end corner of BOX. M
- * WidthX: Width of BOX (X axis). M
- * WidthY: Depth of BOX( Y axis). M
- * WidthZ: Height of BOX( Z axis). M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A BOX primitive M
- * *
- * KEYWORDS: M
- * PrimGenBOXObject, box, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenBOXObject(VectorType Pt,
- RealType WidthX,
- RealType WidthY,
- RealType WidthZ)
- {
- VectorType Dir1, Dir2, Dir3;
-
- PT_CLEAR(Dir1); Dir1[0] = WidthX; /* Prepare direction vectors. */
- PT_CLEAR(Dir2); Dir2[1] = WidthY; /* Parallel to main axes. */
- PT_CLEAR(Dir3); Dir3[2] = WidthZ; /* For GBOX call. */
-
- return PrimGenGBOXObject(Pt, Dir1, Dir2, Dir3);
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a GBOX geometric object defined by Pt - the minimum M
- * 3d point, and 3 direction Vectors Dir1, Dir2, Dir3. M
- * If two of the direction vectors are parallel the GBOX degenerates to M
- * a zero volume object. A NULL pointer is returned in that case. M
- * 4 V
- * Order of vertices is as 5 7 V
- * follows in the picture: | 6 | V
- * | | | V
- * (Note vertex 0 is hidden behind edge 2-6) | | | V
- * 1 | 3 V
- * 2 V
- * *
- * PARAMETERS: M
- * Pt: Low end corner of GBOX. M
- * Dir1, Dir2, Dir3: Three independent directional vectors to define GBOX. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A GBOX primitive. M
- * *
- * KEYWORDS: M
- * PrimGenGBOXObject, general box, box, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenGBOXObject(VectorType Pt,
- VectorType Dir1,
- VectorType Dir2,
- VectorType Dir3)
- {
- int i;
- VectorType Temp;
- VectorType V[8]; /* Hold 8 vertices of BOX. */
- IPVertexStruct *PVertex;
- IPPolygonStruct *PPolygon;
- IPObjectStruct *PBox;
-
- GMVecCrossProd(Temp, Dir1, Dir2);
- if (APX_EQ(PT_LENGTH(Temp), 0.0))
- return NULL;
- GMVecCrossProd(Temp, Dir2, Dir3);
- if (APX_EQ(PT_LENGTH(Temp), 0.0))
- return NULL;
- GMVecCrossProd(Temp, Dir3, Dir1);
- if (APX_EQ(PT_LENGTH(Temp), 0.0))
- return NULL;
-
- /* Also the 0..7 sequence is binary decoded such that bit 0 is Dir1, */
- /* bit 1 Dir2, and bit 2 is Dir3 increment: */
- for (i = 0; i < 8; i++) {
- PT_COPY(V[i], Pt);
-
- if (i & 1)
- PT_ADD(V[i], V[i], Dir1);
- if (i & 2)
- PT_ADD(V[i], V[i], Dir2);
- if (i & 4)
- PT_ADD(V[i], V[i], Dir3);
- }
-
- PBox = GenPolyObject("", NULL, NULL); /* Generate the BOX object itself: */
-
- /* And generate the 6 polygons (Bottom, top and 4 sides in this order): */
- PBox -> U.Pl = GenPolygon4Vrtx(V[0], V[1], V[3], V[2], V[4], PBox -> U.Pl);
- PBox -> U.Pl = GenPolygon4Vrtx(V[6], V[7], V[5], V[4], V[0], PBox -> U.Pl);
- PBox -> U.Pl = GenPolygon4Vrtx(V[4], V[5], V[1], V[0], V[2], PBox -> U.Pl);
- PBox -> U.Pl = GenPolygon4Vrtx(V[5], V[7], V[3], V[1], V[0], PBox -> U.Pl);
- PBox -> U.Pl = GenPolygon4Vrtx(V[7], V[6], V[2], V[3], V[1], PBox -> U.Pl);
- PBox -> U.Pl = GenPolygon4Vrtx(V[6], V[4], V[0], V[2], V[3], PBox -> U.Pl);
-
- /* Update the vertices normals using the polygon plane equation: */
- for (PPolygon = PBox -> U.Pl;
- PPolygon != NULL;
- PPolygon = PPolygon -> Pnext) {
- PVertex = PPolygon -> PVertex;
- do {
- PT_COPY(PVertex -> Normal, PPolygon -> Plane);
- PVertex = PVertex -> Pnext;
- }
- while (PVertex != PPolygon -> PVertex);
- }
-
- return PBox;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a CONE geometric object defined by Pt - the base M
- * 3d center point, Dir - the cone direction and height, and base radius R. M
- * See also PrimSetResolution on fineness control of approximation of the M
- * primitive using flat faces. M
- * *
- * PARAMETERS: M
- * Pt: Center location of Base of CONE. M
- * Dir: Direction and distance from Pt to apex of CONE. M
- * R: Radius of Base of the cone. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A CONE Primitive. M
- * *
- * KEYWORDS: M
- * PrimGenCONEObject, cone, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenCONEObject(VectorType Pt, VectorType Dir, RealType R)
- {
- int i;
- RealType Angle, AngleStep;
- PointType LastCirclePt, CirclePt, ApexPt;
- NormalType LastCircleNrml, CircleNrml, ApexNrml;
- MatrixType Mat;
- IPVertexStruct *VBase, *PVertex;
- IPPolygonStruct *PBase;
- IPObjectStruct *PCone;
-
- CGGenTransMatrixZ2Dir(Mat, Pt, Dir, R); /* Transform from unit circle. */
-
- PT_COPY(ApexPt, Pt); /* Find the apex point: Pt + Dir. */
- PT_ADD(ApexPt, ApexPt, Dir);
- PT_NORMALIZE(Dir);
-
- PCone = GenPolyObject("", NULL, NULL); /* Gen. the CONE object itself: */
- /* Also allocate the base polygon header with first vertex on it: */
- PBase = IPAllocPolygon(0, 0, VBase = IPAllocVertex(0, 0, NULL, NULL), NULL);
-
- LastCirclePt[0] = 1.0; /* First point is allways Angle = 0. */
- LastCirclePt[1] = 0.0;
- LastCirclePt[2] = 0.0;
- MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat);
-
- UpdateVertexNormal(LastCircleNrml, LastCirclePt, Pt, TRUE, ApexPt);
-
- PT_COPY(VBase -> Coord, LastCirclePt);/* Update first pt in base polygon.*/
- PT_COPY(VBase -> Normal, Dir);
-
- AngleStep = M_PI * 2 / GlblResolution;
-
- for (i = 1; i <= GlblResolution; i++) { /* Pass the whole base circle. */
- Angle = AngleStep * i; /* Prevent from additive error. */
-
- CirclePt[0] = cos(Angle);
- CirclePt[1] = sin(Angle);
- CirclePt[2] = 0.0;
- MatMultVecby4by4(CirclePt, CirclePt, Mat);
-
- UpdateVertexNormal(CircleNrml, CirclePt, Pt, TRUE, ApexPt);
-
- PCone -> U.Pl = GenPolygon3Vrtx(LastCirclePt, ApexPt,
- CirclePt, Pt, PCone -> U.Pl);
-
- /* Update the normals for this cone side polygon vertices: */
- PVertex = PCone -> U.Pl -> PVertex;
- PT_COPY(PVertex -> Normal, LastCircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- /* The apex normal is the average of the two base vertices: */
- PT_ADD(ApexNrml, CircleNrml, LastCircleNrml);
- PT_NORMALIZE(ApexNrml);
- PT_COPY(PVertex -> Normal, ApexNrml);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- PT_COPY(PVertex -> Normal, CircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
-
- /* And add this vertex to base polygon: */
- if (i == GlblResolution) /* Its last point - make it circular. */
- VBase -> Pnext = PBase -> PVertex;
- else {
- VBase -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
- VBase = VBase -> Pnext;
- PT_COPY(VBase -> Normal, Dir);
- PT_COPY(VBase -> Coord, CirclePt);
- }
-
- PT_COPY(LastCirclePt, CirclePt);/* Save pt in last pt for next time. */
- PT_COPY(LastCircleNrml, CircleNrml);
- }
-
- /* Update base polygon plane equation. */
- IritPrsrUpdatePolyPlane2(PBase, ApexPt);
- IP_SET_CONVEX_POLY(PBase); /* Mark it as convex polygon. */
- PBase -> Pnext = PCone -> U.Pl; /* And stick it into the cone polygons. */
- PCone -> U.Pl = PBase;
-
- return PCone;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a truncated CONE, CON2, geometric object defined by M
- * Pt - the base 3d center point, Dir - the cone direction and height, and M
- * two base radii R1 and R2. M
- * See also PrimSetResolution on fineness control of approximation of the M
- * primitive using flat faces. M
- * *
- * PARAMETERS: M
- * Pt: Center location of Base of CON2. M
- * Dir: Direction and distance from Pt to center of other base of CON2. M
- * R1, R2: Two base radii of the truncated CON2 M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A CON2 Primitive. M
- * *
- * KEYWORDS: M
- * PrimGenCONE2Object, cone, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenCONE2Object(VectorType Pt,
- VectorType Dir,
- RealType R1,
- RealType R2)
- {
- int i;
- RealType Angle, AngleStep;
- PointType LastCirclePt, CirclePt, ApexPt, LastApexPt1, ApexPt1;
- NormalType LastCircleNrml, CircleNrml;
- VectorType InvDir;
- MatrixType Mat1, Mat2;
- IPVertexStruct *VBase1, *VBase2, *PVertex;
- IPPolygonStruct *PBase1, *PBase2;
- IPObjectStruct *PCone;
-
- PT_COPY(ApexPt, Pt); /* Find the apex point: Pt + Dir. */
- PT_ADD(ApexPt, ApexPt, Dir);
- PT_NORMALIZE(Dir);
- PT_COPY(InvDir, Dir);
- PT_SCALE(InvDir, -1.0);
-
- CGGenTransMatrixZ2Dir(Mat1, Pt, Dir, R1); /* Trans. from unit circle. */
- CGGenTransMatrixZ2Dir(Mat2, ApexPt, Dir, R2);
-
- PCone = GenPolyObject("", NULL, NULL); /* Gen. the CONE object itself: */
- /* Also allocate the base polygon header with first vertex on it: */
- PBase1 = IPAllocPolygon(0, 0,
- VBase1 = IPAllocVertex(0, 0, NULL, NULL), NULL);
- PBase2 = IPAllocPolygon(0, 0,
- VBase2 = IPAllocVertex(0, 0, NULL, NULL), NULL);
-
- /* First point is allways at Angle = 0. */
- LastCirclePt[0] = LastApexPt1[0] = 1.0;
- LastCirclePt[1] = LastApexPt1[1] = 0.0;
- LastCirclePt[2] = LastApexPt1[2] = 0.0;
- MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat1);
- MatMultVecby4by4(LastApexPt1, LastApexPt1, Mat2);
-
- UpdateVertexNormal(LastCircleNrml, LastCirclePt, Pt, TRUE, ApexPt);
-
- PT_COPY(VBase1 -> Coord, LastCirclePt);/* Update 1st pt in base1 polygon.*/
- PT_COPY(VBase1 -> Normal, Dir);
- PT_COPY(VBase2 -> Coord, LastApexPt1);/* Update 1st pt in base2 polygon. */
- PT_COPY(VBase2 -> Normal, InvDir);
-
- AngleStep = M_PI * 2 / GlblResolution;
-
- for (i = 1; i <= GlblResolution; i++) { /* Pass the whole base circle. */
- Angle = AngleStep * i; /* Prevent from additive error. */
-
- CirclePt[0] = ApexPt1[0] = cos(Angle);
- CirclePt[1] = ApexPt1[1] = sin(Angle);
- CirclePt[2] = ApexPt1[2] = 0.0;
- MatMultVecby4by4(CirclePt, CirclePt, Mat1);
- MatMultVecby4by4(ApexPt1, ApexPt1, Mat2);
-
- UpdateVertexNormal(CircleNrml, CirclePt, Pt, TRUE, ApexPt);
-
- PCone -> U.Pl = GenPolygon4Vrtx(LastCirclePt, LastApexPt1, ApexPt1,
- CirclePt, Pt, PCone -> U.Pl);
-
- /* Update the normals for this cone side polygon vertices: */
- PVertex = PCone -> U.Pl -> PVertex;
- PT_COPY(PVertex -> Normal, LastCircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- PT_COPY(PVertex -> Normal, LastCircleNrml );
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- PT_COPY(PVertex -> Normal, CircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- PT_COPY(PVertex -> Normal, CircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
-
- /* And add these vertices to base polygons: */
- if (i == GlblResolution) { /* Its last point - make it circular. */
- VBase1 -> Pnext = PBase1 -> PVertex;
- VBase2 -> Pnext = PBase2 -> PVertex;
- }
- else {
- VBase1 -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
- VBase1 = VBase1 -> Pnext;
- PT_COPY(VBase1 -> Coord, CirclePt);
- PT_COPY(VBase1 -> Normal, Dir);
- VBase2 -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
- VBase2 = VBase2 -> Pnext;
- PT_COPY(VBase2 -> Coord, ApexPt1);
- PT_COPY(VBase2 -> Normal, InvDir);
- }
-
- PT_COPY(LastCirclePt, CirclePt);/* Save pt in last pt for next time. */
- PT_COPY(LastApexPt1, ApexPt1);
- PT_COPY(LastCircleNrml, CircleNrml);
- }
-
- /* Update base polygon plane equation. */
- IritPrsrUpdatePolyPlane2(PBase1, ApexPt);
- IP_SET_CONVEX_POLY(PBase1); /* Mark it as convex polygon. */
- /* Update base polygon plane equation. */
- IritPrsrUpdatePolyPlane2(PBase2, Pt);
- IP_SET_CONVEX_POLY(PBase2); /* Mark it as convex polygon. */
-
- PBase1 -> Pnext = PCone -> U.Pl; /* And stick into the cone polygons. */
- PCone -> U.Pl = PBase1;
- PBase2 -> Pnext = PCone -> U.Pl;
- PCone -> U.Pl = PBase2;
-
- return PCone;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a CYLINder geometric object defined by Pt - the base M
- * 3d center point, Dir - the cylinder direction and height, and radius R. M
- * See also PrimSetResolution on fineness control of approximation of the M
- * primitive using flat faces. M
- * *
- * PARAMETERS: M
- * Pt: Center location of Base of CYLINder. M
- * Dir: Direction and distance from Pt to other base of cylinder. M
- * R: Radius of Base of the cylinder. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A CYLINDER Primitive. M
- * *
- * KEYWORDS: M
- * PrimGenCYLINObject, cylinder, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenCYLINObject(VectorType Pt, VectorType Dir, RealType R)
- {
- int i;
- RealType Angle, AngleStep;
- PointType LastCirclePt, CirclePt, TLastCirclePt, TCirclePt, TPt, Dummy;
- VectorType ForwardDir, BackwardDir;
- NormalType LastCircleNrml, CircleNrml;
- MatrixType Mat;
- IPVertexStruct *VBase1, *VBase2, *PVertex;
- IPPolygonStruct *PBase1, *PBase2;
- IPObjectStruct *PCylin;
-
- CGGenTransMatrixZ2Dir(Mat, Pt, Dir, R); /* Transform from unit circle. */
-
- PCylin = GenPolyObject("", NULL, NULL); /* Gen. the CYLIN object itself: */
- /* Also allocate the bases polygon header with first vertex on it: */
- PBase1 = IPAllocPolygon(0, 0,
- VBase1 = IPAllocVertex(0, 0, NULL, NULL), NULL);
- PBase2 = IPAllocPolygon(0, 0,
- VBase2 = IPAllocVertex(0, 0, NULL, NULL), NULL);
-
- PT_ADD(TPt, Pt, Dir); /* Translated circle center (by Dir). */
-
- /* Prepare the normal directions for the two bases: */
- PT_COPY(ForwardDir, Dir);
- PT_NORMALIZE(ForwardDir);
- PT_COPY(BackwardDir, ForwardDir);
- PT_SCALE(BackwardDir, -1.0);
-
- LastCirclePt[0] = 1.0; /* First point is allways Angle = 0. */
- LastCirclePt[1] = 0.0;
- LastCirclePt[2] = 0.0;
- MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat);
-
- UpdateVertexNormal(LastCircleNrml, LastCirclePt, Pt, FALSE, Dummy);
-
- PT_COPY(VBase1 -> Coord, LastCirclePt);/* Update 1st pt in base1 polygon.*/
- PT_COPY(VBase1 -> Normal, ForwardDir);
- PT_ADD(TLastCirclePt, LastCirclePt, Dir); /* Translated circle (by Dir). */
- PT_COPY(VBase2 -> Coord, TLastCirclePt);/*Update 1st pt in base2 polygon.*/
- PT_COPY(VBase2 -> Normal, BackwardDir);
-
- AngleStep = M_PI * 2 / GlblResolution;
-
- for (i = 1; i <= GlblResolution; i++) { /* Pass the whole base circle. */
- Angle = AngleStep * i; /* Prevent from additive error. */
-
- CirclePt[0] = cos(Angle);
- CirclePt[1] = sin(Angle);
- CirclePt[2] = 0.0;
- MatMultVecby4by4(CirclePt, CirclePt, Mat);
-
- UpdateVertexNormal(CircleNrml, CirclePt, Pt, FALSE, Dummy);
-
- PT_ADD(TCirclePt, CirclePt, Dir); /* Translated circle (by Dir). */
-
- PCylin -> U.Pl = GenPolygon4Vrtx(TLastCirclePt, TCirclePt, CirclePt,
- LastCirclePt, Pt, PCylin -> U.Pl);
- /* Update the normals for this cylinder side polygon vertices: */
- PVertex = PCylin -> U.Pl -> PVertex;
- PT_COPY(PVertex -> Normal, LastCircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- PT_COPY(PVertex -> Normal, CircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- PT_COPY(PVertex -> Normal, CircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- PT_COPY(PVertex -> Normal, LastCircleNrml);
- IP_SET_NORMAL_VRTX(PVertex);
-
- /* And add this vertices to the two cylinder bases: */
- /* Note Base1 is build forward, while Base2 is build backward so it */
- /* will be consistent - cross product of 2 consecutive edges will */
- /* point into the model. */
- if (i == GlblResolution) { /* Its last point - make it circular. */
- VBase1 -> Pnext = PBase1 -> PVertex;
- VBase2 -> Pnext = PBase2 -> PVertex;
- }
- else {
- VBase1 -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
- VBase1 = VBase1 -> Pnext;
- PT_COPY(VBase1 -> Coord, CirclePt);
- PT_COPY(VBase1 -> Normal, ForwardDir);
- PBase2 -> PVertex = IPAllocVertex(0, 0, NULL, PBase2 -> PVertex);
- PT_COPY(PBase2 -> PVertex -> Coord, TCirclePt);
- PT_COPY(PBase2 -> PVertex -> Normal, BackwardDir);
- }
-
- PT_COPY(LastCirclePt, CirclePt);/* Save pt in last pt for next time. */
- PT_COPY(TLastCirclePt, TCirclePt);
- PT_COPY(LastCircleNrml, CircleNrml);
- }
-
- /* Update base polygon plane equation. */
- IritPrsrUpdatePolyPlane2(PBase1, TPt);
- IP_SET_CONVEX_POLY(PBase1); /* Mark it as convex polygon. */
- PBase1 -> Pnext = PCylin -> U.Pl; /* And stick it into cylin polygons. */
- PCylin -> U.Pl = PBase1;
- /* Update base polygon plane equation. */
- IritPrsrUpdatePolyPlane2(PBase2, Pt);
- IP_SET_CONVEX_POLY(PBase2); /* Mark it as convex polygon. */
- PBase2 -> Pnext = PCylin -> U.Pl; /* And stick it into cylin polygons. */
- PCylin -> U.Pl = PBase2;
-
- return PCylin;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a SPHERE geometric object defined by Center, the M
- * center of the sphere and R, its radius. M
- * See also PrimSetResolution on fineness control of approximation of the M
- * primitive using flat faces. M
- * *
- * PARAMETERS: M
- * Center: Center location of SPHERE. M
- * R Radius of sphere. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A SPHERE Primitive. M
- * *
- * KEYWORDS: M
- * PrimGenSPHEREObject, sphere, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenSPHEREObject(VectorType Center, RealType R)
- {
- int i, j, k;
- RealType TetaAngle, TetaAngleStep, FeeAngle, FeeAngleStep,
- CosFeeAngle1, SinFeeAngle1, CosFeeAngle2, SinFeeAngle2;
- PointType LastCircleLastPt, LastCirclePt, CirclePt, CircleLastPt, Dummy;
- IPVertexStruct *PVertex;
- IPObjectStruct *PSphere;
-
- PSphere = GenPolyObject("", NULL, NULL);/* Gen the SPHERE object itself: */
-
- TetaAngleStep = M_PI * 2.0 / GlblResolution; /* Runs from 0 to 2*PI. */
- FeeAngleStep = M_PI * 2.0 / GlblResolution; /* Runs from -PI/2 yo +PI/2. */
-
- /* Generate the lowest (south pole) triangular polygons: */
- FeeAngle = (-M_PI/2.0) + FeeAngleStep; /* First circle above south pole. */
- CosFeeAngle1 = cos(FeeAngle) * R;
- SinFeeAngle1 = sin(FeeAngle) * R;
- PT_COPY(LastCirclePt, Center); /* Calculate the south pole. */
- LastCirclePt[2] -= R;
- PT_COPY(CircleLastPt, Center); /* Calc. last point on current circle. */
- CircleLastPt[0] += CosFeeAngle1;
- CircleLastPt[2] += SinFeeAngle1;
-
- for (i = 1; i <= GlblResolution; i++) {/* Pass whole (horizontal) circle.*/
- TetaAngle = TetaAngleStep * i; /* Prevent from additive error. */
-
- PT_COPY(CirclePt, Center); /* Calc. current point on current circle. */
- CirclePt[0] += cos(TetaAngle) * CosFeeAngle1;
- CirclePt[1] += sin(TetaAngle) * CosFeeAngle1;
- CirclePt[2] += SinFeeAngle1;
-
- PSphere -> U.Pl = GenPolygon3Vrtx(LastCirclePt, CircleLastPt,
- CirclePt, Center, PSphere -> U.Pl);
- /* Update normals: */
- for (j = 0, PVertex = PSphere -> U.Pl -> PVertex;
- j < 3;
- j++, PVertex = PVertex -> Pnext) {
- UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, Center,
- FALSE, Dummy);
- IP_SET_NORMAL_VRTX(PVertex);
- }
-
- PT_COPY(CircleLastPt, CirclePt);/* Save pt in last pt for next time. */
- }
-
- /* Generate the middle rectangular polygons: */
- for (i = 1; i < GlblResolution / 2 - 1; i++) {/* For all horiz. circles. */
- FeeAngle = (-M_PI/2.0) + FeeAngleStep * i;
- CosFeeAngle1 = cos(FeeAngle) * R;
- SinFeeAngle1 = sin(FeeAngle) * R;
- FeeAngle = (-M_PI/2.0) + FeeAngleStep * (i + 1);
- CosFeeAngle2 = cos(FeeAngle) * R;
- SinFeeAngle2 = sin(FeeAngle) * R;
- PT_COPY(CircleLastPt, Center);/* Calc. last point on current circle. */
- CircleLastPt[0] += CosFeeAngle2;
- CircleLastPt[2] += SinFeeAngle2;
- PT_COPY(LastCircleLastPt, Center);/* Calc. last point on last circle.*/
- LastCircleLastPt[0] += CosFeeAngle1;
- LastCircleLastPt[2] += SinFeeAngle1;
-
- for (j = 1; j <= GlblResolution; j++) {/* Pass whole (horiz.) circle.*/
- TetaAngle = TetaAngleStep * j; /* Prevent from additive error. */
-
- PT_COPY(CirclePt, Center);/* Calc. current pt on current circle. */
- CirclePt[0] += cos(TetaAngle) * CosFeeAngle2;
- CirclePt[1] += sin(TetaAngle) * CosFeeAngle2;
- CirclePt[2] += SinFeeAngle2;
- PT_COPY(LastCirclePt, Center);/* Calc. current pt on last circle.*/
- LastCirclePt[0] += cos(TetaAngle) * CosFeeAngle1;
- LastCirclePt[1] += sin(TetaAngle) * CosFeeAngle1;
- LastCirclePt[2] += SinFeeAngle1;
-
- PSphere -> U.Pl = GenPolygon4Vrtx(LastCirclePt, LastCircleLastPt,
- CircleLastPt, CirclePt, Center, PSphere -> U.Pl);
- /* Update normals: */
- for (k = 0, PVertex = PSphere -> U.Pl -> PVertex;
- k < 4;
- k++, PVertex = PVertex -> Pnext) {
- UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, Center,
- FALSE, Dummy);
- IP_SET_NORMAL_VRTX(PVertex);
- }
-
- PT_COPY(CircleLastPt, CirclePt); /* Save pt in last pt. */
- PT_COPY(LastCircleLastPt, LastCirclePt);
- }
- }
-
- /* Generate the upper most (north pole) triangular polygons: */
- FeeAngle = (M_PI/2.0) - FeeAngleStep; /* First circle below north pole. */
- CosFeeAngle1 = cos(FeeAngle) * R;
- SinFeeAngle1 = sin(FeeAngle) * R;
- PT_COPY(LastCirclePt, Center); /* Calculate the north pole. */
- LastCirclePt[2] += R;
- PT_COPY(CircleLastPt, Center); /* Calc. last point on current circle. */
- CircleLastPt[0] += CosFeeAngle1;
- CircleLastPt[2] += SinFeeAngle1;
-
- for (i = 1; i <= GlblResolution; i++) {/* Pass whole (horizontal) circle.*/
- TetaAngle = TetaAngleStep * i; /* Prevent from additive error. */
-
- PT_COPY(CirclePt, Center); /* Calc. current point on current circle. */
- CirclePt[0] += cos(TetaAngle) * CosFeeAngle1;
- CirclePt[1] += sin(TetaAngle) * CosFeeAngle1;
- CirclePt[2] += SinFeeAngle1;
-
- PSphere -> U.Pl = GenPolygon3Vrtx(LastCirclePt, CirclePt, CircleLastPt,
- Center, PSphere -> U.Pl);
-
- /* Update normals: */
- for (j = 0, PVertex = PSphere -> U.Pl -> PVertex;
- j < 3;
- j++, PVertex = PVertex -> Pnext) {
- UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, Center,
- FALSE, Dummy);
- IP_SET_NORMAL_VRTX(PVertex);
- }
-
- PT_COPY(CircleLastPt, CirclePt);/* Save pt in last pt for next time. */
- }
-
- return PSphere;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a TORUS geometric object defined by Center - torus 3d M
- * center point, the main torus plane normal Normal, major radius Rmajor and M
- * minor radius Rminor (Tube radius). M
- * Teta runs on the major circle, Fee on the minor one. Then M
- * X = (Rmajor + Rminor * cos(Fee)) * cos(Teta) V
- * Y = (Rmajor + Rminor * cos(Fee)) * sin(Teta) V
- * Z = Rminor * sin(Fee) V
- * See also PrimSetResolution on fineness control of approximation of the M
- * primitive using flat faces. M
- * *
- * PARAMETERS: M
- * Center: Center location of the TORUS primitive. M
- * Normal: Normal to the major plane of the torus. M
- * Rmajor: Major radius of torus. M
- * Rminor: Minor radius of torus. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A TOURS Primitive. M
- * *
- * KEYWORDS: M
- * PrimGenTORUSObject, torus, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenTORUSObject(VectorType Center,
- VectorType Normal,
- RealType Rmajor,
- RealType Rminor)
- {
- int i, j;
- RealType TetaAngle, TetaAngleStep, FeeAngle, FeeAngleStep,
- CosFeeAngle1, SinFeeAngle1, CosFeeAngle2, SinFeeAngle2;
- PointType LastCircleLastPt, LastCirclePt, CirclePt, CircleLastPt,
- LastInPt, InPt, Dummy;
- MatrixType Mat;
- IPVertexStruct *PVertex;
- IPObjectStruct *PTorus;
-
- CGGenTransMatrixZ2Dir(Mat, Center, Normal, 1.0);/* Trans from unit circ. */
-
- PTorus = GenPolyObject("", NULL, NULL); /* Gen. the Torus object itself: */
-
- TetaAngleStep = M_PI * 2.0 / GlblResolution; /* Runs from 0 to 2*PI. */
- FeeAngleStep = M_PI * 2.0 / GlblResolution; /* Runs from 0 to 2*PI. */
-
- for (i = 1; i <= GlblResolution; i++) {
- FeeAngle = FeeAngleStep * (i - 1);
- CosFeeAngle1 = cos(FeeAngle) * Rminor;
- SinFeeAngle1 = sin(FeeAngle) * Rminor;
- FeeAngle = FeeAngleStep * i;
- CosFeeAngle2 = cos(FeeAngle) * Rminor;
- SinFeeAngle2 = sin(FeeAngle) * Rminor;
- LastCircleLastPt[0] = Rmajor + CosFeeAngle1;
- LastCircleLastPt[1] = 0.0;
- LastCircleLastPt[2] = SinFeeAngle1;
- MatMultVecby4by4(LastCircleLastPt, LastCircleLastPt, Mat);
- LastCirclePt[0] = Rmajor + CosFeeAngle2;
- LastCirclePt[1] = 0.0;
- LastCirclePt[2] = SinFeeAngle2;
- MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat);
- /* Point inside the object relative to this polygon: */
- LastInPt[0] = Rmajor;
- LastInPt[1] = 0.0;
- LastInPt[2] = 0.0;
- MatMultVecby4by4(LastInPt, LastInPt, Mat);
-
- for (j = 1; j <= GlblResolution; j++) {
- TetaAngle = TetaAngleStep * j; /* Prevent from additive error. */
-
- CircleLastPt[0] = (Rmajor + CosFeeAngle1) * cos(TetaAngle);
- CircleLastPt[1] = (Rmajor + CosFeeAngle1) * sin(TetaAngle);
- CircleLastPt[2] = SinFeeAngle1;
- MatMultVecby4by4(CircleLastPt, CircleLastPt, Mat);
- CirclePt[0] = (Rmajor + CosFeeAngle2) * cos(TetaAngle);
- CirclePt[1] = (Rmajor + CosFeeAngle2) * sin(TetaAngle);
- CirclePt[2] = SinFeeAngle2;
- MatMultVecby4by4(CirclePt, CirclePt, Mat);
- /* Point inside the object relative to this polygon: */
- InPt[0] = Rmajor * cos(TetaAngle);
- InPt[1] = Rmajor * sin(TetaAngle);
- InPt[2] = 0.0;
- MatMultVecby4by4(InPt, InPt, Mat);
-
- PTorus -> U.Pl = GenPolygon4Vrtx(CirclePt, CircleLastPt,
- LastCircleLastPt, LastCirclePt, InPt, PTorus -> U.Pl);
-
- /* Update normals: */
- PVertex = PTorus -> U.Pl -> PVertex;
- UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, InPt,
- FALSE, Dummy);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, InPt,
- FALSE, Dummy);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, LastInPt,
- FALSE, Dummy);
- IP_SET_NORMAL_VRTX(PVertex);
- PVertex = PVertex -> Pnext;
- UpdateVertexNormal(PVertex -> Normal, PVertex -> Coord, LastInPt,
- FALSE, Dummy);
- IP_SET_NORMAL_VRTX(PVertex);
-
- PT_COPY(LastCirclePt, CirclePt); /* Save pt in last pt. */
- PT_COPY(LastCircleLastPt, CircleLastPt);
- PT_COPY(LastInPt, InPt);
- }
- }
-
- return PTorus;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a POLYDISK geometric object defined by the normal N M
- * and the translation vector T. The object is a planar disk (a circle of M
- * GlblResolution points in it...) and its radius is equal to R. M
- * The normal direction is assumed to point to the inside of the object. M
- * See also PrimSetResolution on fineness control of approximation of the M
- * primitive using flat faces. M
- * *
- * PARAMETERS: M
- * N: Normal to the plane this disk included in. M
- * T: A translation factor of the center of the disk. M
- * R: Radius of teh disk. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A single polygon object - a disk. M
- * *
- * KEYWORDS: M
- * PrimGenPOLYDISKObject, disk, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenPOLYDISKObject(VectorType N, VectorType T, RealType R)
- {
- int i;
- RealType Angle, AngleStep;
- PointType CirclePt;
- MatrixType Mat;
- IPVertexStruct *V;
- IPPolygonStruct *PCirc;
- IPObjectStruct *PPDisk;
-
- CGGenTransMatrixZ2Dir(Mat, T, N, R); /* Transform from unit circle. */
- PT_NORMALIZE(N);
-
- PPDisk = GenPolyObject("", NULL, NULL); /* Gen. the PLANE object itself: */
- PCirc = IPAllocPolygon(0, 0, V = IPAllocVertex(0, 0, NULL, NULL), NULL);
- PPDisk -> U.Pl = PCirc;
-
- CirclePt[0] = 1.0; /* First point is allways Angle = 0. */
- CirclePt[1] = 0.0;
- CirclePt[2] = 0.0;
- MatMultVecby4by4(CirclePt, CirclePt, Mat);
- PT_COPY(V -> Coord, CirclePt); /* Update first pt in circle polygon. */
- PT_COPY(V -> Normal, N);
-
- AngleStep = M_PI * 2 / GlblResolution;
-
- for (i = 1; i <= GlblResolution; i++) { /* Pass the whole base circle. */
- Angle = AngleStep * i; /* Prevent from additive error. */
-
- CirclePt[0] = cos(Angle);
- CirclePt[1] = sin(Angle);
- CirclePt[2] = 0.0;
-
- MatMultVecby4by4(CirclePt, CirclePt, Mat);
-
- /* And add this vertices to the two cylinder bases: */
- if (i == GlblResolution) { /* Its last point - make it circular. */
- V -> Pnext = PCirc -> PVertex;
- }
- else {
- V -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
- V = V -> Pnext;
- PT_COPY(V -> Coord, CirclePt);
- PT_COPY(V -> Normal, N);
- }
- }
-
- PT_ADD(CirclePt, CirclePt, N); /* Make a point "IN" the circle object. */
- /* Update base polygon plane equation. */
- IritPrsrUpdatePolyPlane2(PCirc, CirclePt);
- IP_SET_CONVEX_POLY(PCirc); /* Mark it as convex polygon. */
-
- return PPDisk;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create a POLYGON/LINE directly from its specified vertices. M
- * The validity of the elements in the provided list is tested to make sure M
- * they are vectors or points. M
- * No test is made to make sure all vertices are on one plane, and that no M
- * two vertices are similar. M
- * *
- * PARAMETERS: M
- * PObjList: List of vertices/points to construct as a polygon/line. M
- * IsPolyline: If TRUE, make a polyline, otherwise a polygon. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A polygon/line constructed from PObjList. M
- * *
- * KEYWORDS: M
- * PrimGenPOLYGONObject, polygon, polyline, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenPOLYGONObject(IPObjectStruct *PObjList, int IsPolyline)
- {
- int i,
- NumVertices = 0;
- IPVertexStruct *V, *VHead,
- *VTail = NULL;
- IPPolygonStruct *PPoly;
- IPObjectStruct *PObj, *PObjPoly;
-
- if (!IP_IS_OLST_OBJ(PObjList))
- IritFatalError("GenPOLYObject: Not object list object!");
-
- i = 0;
- while ((PObj = ListObjectGet(PObjList, i++)) != NULL) {
- if (!IP_IS_VEC_OBJ(PObj) &&
- !IP_IS_POINT_OBJ(PObj) &&
- !IP_IS_CTLPT_OBJ(PObj)) {
- IritWarningError("None vector object found in list, empty object result.");
- return NULL;
- }
- NumVertices++;
- }
-
- if (NumVertices < 2 + !IsPolyline) {
- IritWarningError("Too few vertices, empty object result.");
- return NULL;
- }
-
- PPoly = IPAllocPolygon(0, 0, VHead = NULL, NULL);
- i = 0;
- while ((PObj = ListObjectGet(PObjList, i++)) != NULL) {
- V = IPAllocVertex(0, 0, NULL, NULL);
- if (IP_IS_VEC_OBJ(PObj))
- PT_COPY(V -> Coord, PObj -> U.Vec);
- else if (IP_IS_POINT_OBJ(PObj))
- PT_COPY(V -> Coord, PObj -> U.Pt);
- else if (IP_IS_CTLPT_OBJ(PObj)) {
- IPObjectStruct
- *PVec = IritPrsrCoerceObjectTo(PObj, IP_OBJ_VECTOR);
-
- PT_COPY(V -> Coord, PVec -> U.Vec);
- IPFreeObject(PVec);
- }
-
- if (VHead == NULL) {
- PPoly -> PVertex = VHead = VTail = V;
- }
- else {
- VTail -> Pnext = V;
- VTail = V;
- }
- }
-
- PObjPoly = GenPolyObject("", NULL, NULL); /* Gen. POLY object itself: */
- PObjPoly -> U.Pl = PPoly;
- if (IsPolyline) {
- IP_SET_POLYLINE_OBJ(PObjPoly);
- }
- else {
- IP_SET_POLYGON_OBJ(PObjPoly);
-
- VTail -> Pnext = VHead; /* Close the vertex list loop. */
-
- /* Update polygon plane equation and vertices normals. */
- CGPlaneFrom3Points(PPoly -> Plane, VHead -> Coord,
- VHead -> Pnext -> Coord,
- VHead -> Pnext -> Pnext -> Coord);
- V = VHead;
- do {
- PT_COPY(V -> Normal, PPoly -> Plane);
- V = V -> Pnext;
- }
- while (V != VHead);
- }
-
- return PObjPoly;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to create an OBJECT directly from set of sspecified polygons. m
- * No test is made for the validity of the model in any sense. M
- * *
- * PARAMETERS: M
- * PObjList: List of polygonal objects. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A single object containing all polygons in all M
- * provided objects, by a simple union. M
- * *
- * KEYWORDS: M
- * PrimGenObjectFromPolyList, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenObjectFromPolyList(IPObjectStruct *PObjList)
- {
- int i;
- IPPolygonStruct *PPoly,
- *PTail = NULL;
- IPObjectStruct *PObj, *PObjPoly;
-
- if (!IP_IS_OLST_OBJ(PObjList))
- IritFatalError("GenObjectFromPolyList: Not object list object!");
-
- i = 0;
- while ((PObj = ListObjectGet(PObjList, i++)) != NULL) {
- if (!IP_IS_POLY_OBJ(PObj)) {
- IritWarningError("None polygon object found in list, empty object result.");
- return NULL;
- }
- }
-
- PObjPoly = GenPolyObject("", NULL, NULL);/* Gen. the POLY object itself: */
- i = 0;
- while ((PObj = ListObjectGet(PObjList, i)) != NULL) {
- if (i++ == 0) {
- if (IP_IS_POLYLINE_OBJ(PObj))
- IP_SET_POLYLINE_OBJ(PObjPoly);
- else
- IP_SET_POLYGON_OBJ(PObjPoly);
- }
- else {
- if ((IP_IS_POLYLINE_OBJ(PObj) && !IP_IS_POLYLINE_OBJ(PObjPoly)) ||
- (IP_IS_POLYGON_OBJ(PObj) && !IP_IS_POLYGON_OBJ(PObjPoly))) {
- IritWarningError("Polygons mixed with polylines.");
- return NULL;
- }
- }
-
- PPoly = CopyPolygonList(PObj -> U.Pl);
-
- if (PTail == NULL) {
- PObjPoly -> U.Pl = PPoly;
- }
- else {
- PTail -> Pnext = PPoly;
- }
- for (PTail = PPoly; PTail -> Pnext != NULL; PTail = PTail -> Pnext);
- }
-
- return PObjPoly;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Not supported. *
- * *
- * PARAMETERS: *
- * PObj: *
- * *
- * RETURN VALUE: *
- * IPObjectStruct *: *
- *****************************************************************************/
- IPObjectStruct *PrimGenCROSSECObject(IPObjectStruct *PObj)
- {
- if (PObj && !IP_IS_POLY_OBJ(PObj))
- IritFatalError("CrossSec: operation on non polygonal object");
-
- IritWarningError("GenCrossSecObject not implemented");
-
- return NULL;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to a create surface of revolution by rotating the given cross M
- * section along the Z axis. M
- * Input can either be a polygon/line or a freefrom curve object. M
- * If input is a polyline/gon, it must never be coplanar with the Z axis. M
- * See also PrimSetResolution on fineness control of approximation of the M
- * primitive using flat faces. M
- * *
- * PARAMETERS: M
- * Cross: To rotate around the Z axis forming a surface of revolution. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: A surface of revolution. M
- * *
- * KEYWORDS: M
- * PrimGenSURFREVObject, surface of revolution, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenSURFREVObject(IPObjectStruct *Cross)
- {
- int i, j;
- RealType XYSize;
- MatrixType Mat; /* Rotation Matrix around Z axes. */
- IPVertexStruct *V, *V1, *V1Head, *V2, *V2Head, *VIn, *VInHead;
- IPPolygonStruct *Pl1, *Pl2, *PlIn, *PlNew = NULL;
- IPObjectStruct *PSurfRev;
-
- if (!IP_IS_POLY_OBJ(Cross) && !IP_IS_CRV_OBJ(Cross)) {
- IritWarningError("Cross section is not poly/crv. Empty object result");
- return NULL;
- }
-
- if (IP_IS_POLY_OBJ(Cross)) {
- if (APX_EQ(Cross -> U.Pl -> Plane[0], 0.0) &&
- APX_EQ(Cross -> U.Pl -> Plane[1], 0.0)) {
- IritWarningError("Cross-section perpendicular to Z. Empty object result");
- return NULL;
- }
-
- Pl1 = IPAllocPolygon(0, 0,
- V1Head = CopyVertexList(Cross -> U.Pl -> PVertex), NULL);
- PLANE_COPY(Pl1 -> Plane, Cross -> U.Pl -> Plane);
- Pl2 = IPAllocPolygon(0, 0,
- V2Head = CopyVertexList(Cross -> U.Pl -> PVertex), NULL);
- PLANE_COPY(Pl2 -> Plane, Cross -> U.Pl -> Plane);
- PlIn = GenInsidePoly(Pl1);
- VInHead = PlIn -> PVertex;
- MatGenMatRotZ1(2.0 * M_PI / GlblResolution, Mat);
-
- for (i = 0; i < GlblResolution; i++)
- {
- V2 = V2Head;
- do {
- MatMultVecby4by4(V2 -> Coord, V2 -> Coord , Mat);
- V2 = V2 -> Pnext;
- }
- while (V2 != NULL && V2 != V2Head);
-
- V1 = V1Head;
- if (i < GlblResolution - 1) /* If this is last loop use original */
- V2 = V2Head; /* poly as we might accumulate error during the */
- else /* transformations along the circle. */
- V2 = Cross -> U.Pl -> PVertex;
- VIn = VInHead;
-
- do {
- PlNew = GenPolygon4Vrtx(V1 -> Coord, V1 -> Pnext -> Coord,
- V2 -> Pnext -> Coord, V2 -> Coord,
- VIn -> Coord, PlNew);
-
- /* Update normals: */
- for (j = 0, V = PlNew -> PVertex; j < 4; j++, V = V -> Pnext) {
- V -> Normal[0] = V -> Coord[0];
- V -> Normal[1] = V -> Coord[1];
- V -> Normal[2] = 0.0;
- /* Make sure normal does not point in opposite direction.*/
- if (DOT_PROD(V -> Normal, PlNew -> Plane) < 0.0)
- PT_SCALE(V -> Normal, -1.0);
-
- /* Since Z normal component should be fixed for all normals: */
- V -> Normal[2] = PlNew -> Plane[2];
- XYSize = APX_EQ(ABS(PlNew -> Plane[2]), 1.0) ?
- 0.0 : 1 - SQR(PlNew -> Plane[2]);
- XYSize = sqrt(XYSize / (SQR(V -> Coord[0]) +
- SQR(V -> Coord[1])));
- V -> Normal[0] *= XYSize;
- V -> Normal[1] *= XYSize;
- }
-
- VIn = VIn -> Pnext;
- V1 = V1 -> Pnext;
- V2 = V2 -> Pnext;
- }
- while (V1 -> Pnext != NULL && V1 != V1Head);
-
- V1 = V1Head;
- do {
- MatMultVecby4by4(V1 -> Coord, V1 -> Coord , Mat);
- V1 = V1 -> Pnext;
- }
- while (V1 != NULL && V1 != V1Head);
- VIn = VInHead;
- do {
- MatMultVecby4by4(VIn -> Coord, VIn -> Coord , Mat);
- VIn = VIn -> Pnext;
- }
- while (VIn != NULL && VIn != VInHead);
- }
-
- IPFreePolygonList(PlIn);
- IPFreePolygonList(Pl1);
- IPFreePolygonList(Pl2);
-
- PSurfRev = GenPolyObject("", NULL, NULL);
- PSurfRev -> U.Pl = PlNew;
-
- return PSurfRev;
- }
- else if (IP_IS_CRV_OBJ(Cross)) {
- if (CAGD_NUM_OF_PT_COORD(Cross -> U.Crvs -> PType) < 3) {
- IritWarningError("Cross-section perpendicular to Z. Empty object result");
- return NULL;
- }
-
- PSurfRev = GenSRFObject(CagdSurfaceRev(Cross -> U.Crvs));
- return PSurfRev;
- }
- else
- return NULL;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to a create an extrusion surface out of the given cross section M
- * and the given direction. M
- * Input can either be a polygon/line or a freefrom curve object. M
- * If input is a polyline/gon, it must never be coplanar with Dir. M
- * See also PrimSetResolution on fineness control of approximation of the M
- * primitive using flat faces. M
- * M
- * PARAMETERS: M
- * Cross: To extrude in direction Dir. M
- * Dir: Direction and magnitude of extrusion. M
- * *
- * RETURN VALUE: M
- * IPObjectStruct *: An extrusion surface. M
- * *
- * KEYWORDS: M
- * PrimGenEXTRUDEObject, extrusion surface, primitives M
- *****************************************************************************/
- IPObjectStruct *PrimGenEXTRUDEObject(IPObjectStruct *Cross, VectorType Dir)
- {
- int i;
- RealType R;
- CagdVecStruct CagdDir;
- IPVertexStruct *V1, *V1Head, *V2, *VIn;
- IPPolygonStruct *PBase1, *PBase2, *Pl, *PlIn;
- IPObjectStruct *PExtrude;
-
- if (!IP_IS_POLY_OBJ(Cross) && !IP_IS_CRV_OBJ(Cross)) {
- IritWarningError("Cross section is not poly/crv. Empty object result");
- return NULL;
- }
-
- if (IP_IS_POLY_OBJ(Cross)) {
- R = DOT_PROD(Cross -> U.Pl -> Plane, Dir);
- if (APX_EQ(R, 0.0)) {
- IritWarningError("Extrusion direction in cross-section plane. Empty object result");
- return NULL;
- }
-
- /* Prepare two bases (update their plane normal to point INDISE): */
- PBase1 = IPAllocPolygon(0, 0,
- CopyVertexList(Cross -> U.Pl -> PVertex), NULL);
- Pl = PBase2 = IPAllocPolygon(0, 0,
- CopyVertexList(Cross -> U.Pl -> PVertex), PBase1);
- V1 = V1Head = PBase2 -> PVertex;
- do {
- PT_ADD(V1 -> Coord, Dir, V1 -> Coord);
- V1 = V1 -> Pnext;
- }
- while (V1 != NULL && V1 != V1Head);
- if (R > 0.0) {
- PLANE_COPY(PBase1 -> Plane, Cross -> U.Pl -> Plane);
- for (i = 0; i < 3; i++)
- PBase2 -> Plane[i] = (-Cross -> U.Pl -> Plane[i]);
- PBase2 -> Plane[3] = (-DOT_PROD(PBase2 -> Plane,
- PBase2 -> PVertex -> Coord));
- }
- else {
- for (i = 0; i < 4; i++)
- PBase1 -> Plane[i] = (-Cross -> U.Pl -> Plane[i]);
- PLANE_COPY(PBase2 -> Plane, Cross -> U.Pl -> Plane);
- PBase2 -> Plane[3] = (-DOT_PROD(PBase2 -> Plane,
- PBase2 -> PVertex -> Coord));
- }
-
- /* Now generate all the 4 corner polygon between the two bases: */
- V1 = V1Head = PBase1 -> PVertex;
- V2 = PBase2 -> PVertex;
- PlIn = GenInsidePoly(PBase1);
- VIn = PlIn -> PVertex;
- do {
- Pl = GenPolygon4Vrtx(V1 -> Coord, V1 -> Pnext -> Coord,
- V2 -> Pnext -> Coord, V2 -> Coord, VIn -> Coord, Pl);
- VIn = VIn -> Pnext;
- V1 = V1 -> Pnext;
- V2 = V2 -> Pnext;
- }
- while (V1 -> Pnext != NULL && V1 != V1Head);
-
- IPFreePolygonList(PlIn);
-
- PExtrude = GenPolyObject("", NULL, NULL);
- PExtrude -> U.Pl = Pl;
-
- /* Update all the polygon vertices normals. */
- for (Pl = PExtrude -> U.Pl; Pl != NULL; Pl = Pl -> Pnext) {
- V1 = V1Head = Pl -> PVertex;
- do {
- PT_COPY(V1 -> Normal, Pl -> Plane);
- V1 = V1 -> Pnext;
- }
- while (V1 != NULL && V1 != V1Head);
- }
-
- return PExtrude;
- }
- else if (IP_IS_CRV_OBJ(Cross)) {
- for (i = 0; i < 3; i++)
- CagdDir.Vec[i] = Dir[i];
- PExtrude = GenSRFObject(CagdExtrudeSrf(Cross -> U.Crvs, &CagdDir));
-
- return PExtrude;
- }
- else
- return NULL;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to create a pseudo polygon out of a given polygon such that each *
- * vertex Vi is in the inside side of the corresponding edge ViVi+1 in the *
- * given polygon. Used in polygon generation for EXTRUDE/SURFREV operations. *
- * *
- * PARAMETERS: *
- * Pl: Input polygon *
- * *
- * RETURN VALUE: *
- * IPPolygonStruct *: Pseudo one. *
- *****************************************************************************/
- static IPPolygonStruct *GenInsidePoly(IPPolygonStruct *Pl)
- {
- int Axes;
- RealType Dx, Dy;
- PointType Pt;
- MatrixType Mat;
- IPPolygonStruct *PlIn;
- IPVertexStruct *VHead, *V, *Vnext, *VInHead,
- *VIn = NULL;
-
- PlIn = IPAllocPolygon(0, 0, VInHead = NULL, NULL);
-
- /* Generate transformation matrix to bring polygon to a XY parallel */
- /* plane, and transform a copy of the polygon to that plane. */
- GenRotateMatrix(Mat, Pl -> Plane);
- /* We dont want to modify original! */
- VHead = V = CopyVertexList(Pl -> PVertex);
- Pl = IPAllocPolygon(0, 0, VHead, NULL);
- do {
- MatMultVecby4by4(V -> Coord, V -> Coord, Mat);
- V = V -> Pnext;
- }
- while (V != NULL && V != VHead);
-
- V = VHead;
- do {
- Vnext = V -> Pnext;
- Dx = ABS(V -> Coord[0] - Vnext -> Coord[0]);
- Dy = ABS(V -> Coord[1] - Vnext -> Coord[1]);
- /* Prepare middle point. */
- Pt[0] = (V -> Coord[0] + Vnext -> Coord[0]) / 2.0;
- Pt[1] = (V -> Coord[1] + Vnext -> Coord[1]) / 2.0;
- Pt[2] = V -> Coord[2];
- /* If Dx > Dy fire ray in +Y direction, otherwise in +X direction */
- /* and if number of intersections is even (excluding the given point */
- /* itself) then that direction is the outside, otherwise, its inside.*/
- Axes = (Dx > Dy ? 1 : 0);
- if (CGPolygonRayInter(Pl, Pt, Axes) % 2 == 0) {
- /* The amount we move along Axes is not of a big meaning as long */
- /* as it is not zero, so MAX(Dx, Dy) guarantee non zero value... */
- Pt[Axes] -= MAX(Dx, Dy);
- }
- else {
- Pt[Axes] += MAX(Dx, Dy);
- }
-
- /* Now Pt holds point which is in the inside part of vertex V, Vnext.*/
- /* Put it in the pseudo inside polygon PlIn: */
- if (VInHead) {
- VIn -> Pnext = IPAllocVertex(0, 0, NULL, NULL);
- VIn = VIn -> Pnext;
- }
- else {
- PlIn -> PVertex = VInHead = VIn = IPAllocVertex(0, 0, NULL, NULL);
- }
- PT_COPY(VIn -> Coord, Pt);
-
- V = Vnext;
- }
- while (V != NULL && V != VHead);
- VIn -> Pnext = VInHead;
-
- IPFreePolygonList(Pl); /* Free copied (and trans.) vrtx list. */
-
- /* Transform PlIn to the plane where original Pl is... */
- if (!MatInverseMatrix(Mat, Mat)) /* Find the inverse matrix. */
- IritFatalError("GenInsidePoly: Inverse matrix does not exits");
- VIn = VInHead;
- do {
- MatMultVecby4by4(VIn -> Coord, VIn -> Coord, Mat);
- VIn = VIn -> Pnext;
- }
- while (VIn != NULL && VIn != VInHead);
-
- return PlIn;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to create a polygon out of a list of 4 vertices V1/2/3/4. *
- * The fifth vertex is inside (actually, this is not true, as this point *
- * will be in the positive part of the plane, which only locally in the *
- * object...) the object, so the polygon's normal direction can be evaluated *
- * uniquely. *
- * No test is made to make sure the 4 points are co-planar... *
- * The points are placed in order. *
- * *
- * PARAMETERS: *
- * V1, V2, V3, V4: Four vertices of the constructed polygon. *
- * Vin: A vertex that can be assumed to be inside the *
- * object for normal evaluation of the plane of polygon. *
- * Pnext: Next is chain of polygons, in linked list. *
- * *
- * RETURN VALUE: *
- * IPPolygonStruct *: The constructed polygon. *
- *****************************************************************************/
- static IPPolygonStruct *GenPolygon4Vrtx(VectorType V1,
- VectorType V2,
- VectorType V3,
- VectorType V4,
- VectorType Vin,
- IPPolygonStruct *Pnext)
- {
- IPPolygonStruct *PPoly;
- IPVertexStruct *V;
-
- PPoly = IPAllocPolygon(0, 0, V = IPAllocVertex(0, 0, NULL, NULL), Pnext);
- PT_COPY(V -> Coord, V1);
-
- V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Coord, V2);
-
- V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Coord, V3);
-
- V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Coord, V4);
-
- V -> Pnext = PPoly -> PVertex; /* Make the Vertex list circular. */
-
- IritPrsrUpdatePolyPlane2(PPoly, Vin); /* Update plane equation. */
-
- IP_SET_CONVEX_POLY(PPoly); /* Mark it as convex polygon. */
-
- return PPoly;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to create a polygon out of a list of 3vertices V1/2/3. *
- * The fifth vertex is inside (actually, this is not true, as this point *
- * will be in the positive part of the plane, which only locally in the *
- * object...) the object, so the polygon's normal direction can be evaluated *
- * uniquely. *
- * No test is made to make sure the 4 points are co-planar... *
- * The points are placed in order. *
- * *
- * PARAMETERS: *
- * V1, V2, V3: Three vertices of the constructed polygon. *
- * Vin: A vertex that can be assumed to be inside the *
- * object for normal evaluation of the plane of polygon. *
- * Pnext: Next is chain of polygons, in linked list. *
- * *
- * RETURN VALUE: *
- * IPPolygonStruct *: The constructed polygon. *
- *****************************************************************************/
- static IPPolygonStruct *GenPolygon3Vrtx(VectorType V1,
- VectorType V2,
- VectorType V3,
- VectorType Vin,
- IPPolygonStruct *Pnext)
- {
- IPPolygonStruct *PPoly;
- IPVertexStruct *V;
-
- PPoly = IPAllocPolygon(0, 0, V = IPAllocVertex(0, 0, NULL, NULL), Pnext);
- PT_COPY(V -> Coord, V1);
-
- V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Coord, V2);
-
- V -> Pnext = IPAllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Coord, V3);
-
- V -> Pnext = PPoly -> PVertex; /* Make the Vertex list circular. */
-
- IritPrsrUpdatePolyPlane2(PPoly, Vin); /* Update plane equation. */
-
- IP_SET_CONVEX_POLY(PPoly); /* Mark it as convex polygon. */
-
- return PPoly;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to update the Vertex Pt normal equation. The normal should point *
- * InPt but should be perpendicular to the line Pt-PerpPt if Perpendicular is *
- * TRUE. THe normal is normalized to a unit length. *
- * *
- * PARAMETERS: *
- * Normal: To update. *
- * Pt: The normal belongs to this location. *
- * InPt: To define the normal direction as InPt - Pt. *
- * Perpendicular: If TRUE, Normal also perpedicular to PerpPt - Pt. *
- * PerpPt: To define perpendicular relation as PerpPt - Pt. *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void UpdateVertexNormal(NormalType Normal,
- PointType Pt,
- PointType InPt,
- int Perpendicular,
- PointType PerpPt)
- {
- VectorType V1, V2;
-
- PT_SUB(Normal, InPt, Pt);
-
- if (Perpendicular) {
- PT_SUB(V1, PerpPt, Pt);
- GMVecCrossProd(V2, V1, Normal);
- GMVecCrossProd(Normal, V2, V1);
- }
-
- PT_NORMALIZE(Normal);
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to set the polygonal resolution (fineness). M
- * Resolution sroutghly the number of edges a circular primitive will have M
- * along the entire circle. M
- * *
- * PARAMETERS: M
- * Resolution: To set as new resolution for all primitve constructors. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * PrimSetResolution, primitives, resolution M
- *****************************************************************************/
- void PrimSetResolution(int Resolution)
- {
- GlblResolution = MAX(Resolution, MIN_RESOLUTION);
- }
-