home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * "Irit" - the 3d 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 - cone with any main direction. *
- * 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. *
- *****************************************************************************/
-
- #ifdef __MSDOS__
- #include <graphics.h>
- #endif /* __MSDOS__ */
-
- #include <stdio.h>
- #include <math.h>
- #include "program.h"
- #include "allocatg.h"
- #include "objects.h"
- #include "primitvl.h"
- #include "primitvg.h"
- #include "geomat3d.h"
- #include "windowsg.h"
- #include "convexg.h"
-
- #ifndef __MSDOS__
- #include "xgraphic.h"
- #endif /* __MSDOS__ */
-
- /*****************************************************************************
- * Routine to create a BOX geometric object defined by Pt - the minimun *
- * 3d point, and Width - Dx Dy & Dz vector. 4 *
- * Order of vertices is as 5 7 *
- * follows in the picture: | 6 | *
- * | | | *
- * (Note vertex 0 is hidden behind edge 2-6) | | | *
- * 1 | 3 *
- * 2 *
- *****************************************************************************/
- struct ObjectStruct * GenBOXObject(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 GenGBOXObject(Pt, Dir1, Dir2, Dir3);
- }
-
- /*****************************************************************************
- * Routine to create a GBOX geometric object defined by Pt - the minimun *
- * 3d point, and 3 direction Vectors Dir1, Dir2, Dir3. If two of the *
- * direction vectors are parallel the GBOX converges to zero volume. A NULL *
- * pointer is returned in that case! *
- * 4 *
- * Order of vertices is as 5 7 *
- * follows in the picture: | 6 | *
- * | | | *
- * (Note vertex 0 is hidden behind edge 2-6) | | | *
- * 1 | 3 *
- * 2 *
- *****************************************************************************/
- struct ObjectStruct * GenGBOXObject(VectorType Pt,
- VectorType Dir1, VectorType Dir2, VectorType Dir3)
- {
- int i;
- VectorType Temp;
- VectorType V[8]; /* Hold 8 vertices of BOX. */
- struct ObjectStruct *PBox;
-
- VecCrossProd(Temp, Dir1, Dir2);
- if (APX_EQ(PT_LENGTH(Temp), 0.0)) return NULL;
- VecCrossProd(Temp, Dir2, Dir3);
- if (APX_EQ(PT_LENGTH(Temp), 0.0)) return NULL;
- VecCrossProd(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 = GenGeomObject("", 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);
-
- SET_OBJECT_COLOR(PBox, PrimColor); /* Set its default color. */
-
- return PBox;
- }
-
- /*****************************************************************************
- * Routine to fetch the resolution parameter from the RESOLUTION object. *
- *****************************************************************************/
- static int GetResolution(void)
- {
- int Resolution;
- struct ObjectStruct *PObj = GetObject("RESOLUTION");
-
- if (PObj == NULL || !IS_NUM_OBJ(PObj)) {
- WndwInputWindowPutStr("No numeric object name RESOLUTION is defined",
- RED);
- Resolution = DEFAULT_RESOLUTION;
- }
- else Resolution = MAX(((int) (PObj -> U.R)), MIN_RESOLUTION);
-
- Resolution = (Resolution / 2) * 2; /* Make sure its an even number. */
-
- return Resolution;
- }
-
- /*****************************************************************************
- * Routine to create a CONE geometric object defined by Pt - the base *
- * 3d center point, Dir - the cone direction and length, and base radius R. *
- *****************************************************************************/
- struct ObjectStruct * GenCONEObject(VectorType Pt, VectorType Dir, RealType *R)
- {
- int i, Resolution;
- RealType Angle, AngleStep;
- PointType LastCirclePt, CirclePt, ApexPt;
- MatrixType Mat;
- struct VertexStruct *VBase;
- struct PolygonStruct *PBase;
- struct ObjectStruct *PCone;
-
- Resolution = GetResolution(); /* Get refinement factor of object. */
-
- GenTransformMatrix(Mat, Pt, Dir, *R); /* Transform from unit circle. */
-
- PT_COPY(ApexPt, Pt); /* Find the apex point: Pt + Dir. */
- PT_ADD(ApexPt, ApexPt, Dir);
-
- PCone = GenGeomObject("", NULL, NULL); /* Gen. the CONE object itself: */
- /* Also allocate the base polygon header with first vertex on it: */
- PBase = AllocPolygon(0, 0, VBase = AllocVertex(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);
-
- PT_COPY(VBase -> Pt, LastCirclePt); /* Update first pt in base polygon. */
-
- AngleStep = M_PI * 2 / Resolution;
-
- for (i=1; i<=Resolution; 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);
-
- PCone -> U.Pl = GenPolygon3Vrtx(LastCirclePt, ApexPt, CirclePt,
- Pt, PCone -> U.Pl);
- /* And add this vertex to base polygon: */
- if (i == Resolution) /* Its last point - make it circular. */
- VBase -> Pnext = PBase -> V;
- else {
- VBase -> Pnext = AllocVertex(0, 0, NULL, NULL);
- VBase = VBase -> Pnext;
- PT_COPY(VBase -> Pt, CirclePt);
- }
-
- PT_COPY(LastCirclePt, CirclePt);/* Save pt in last pt for next time. */
- }
-
- UpdatePolyPlane(PBase, ApexPt); /* Update base polygon plane equation. */
- 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;
-
- SET_OBJECT_COLOR(PCone, PrimColor); /* Set its default color. */
-
- return PCone;
- }
-
- /*****************************************************************************
- * Routine to create a CYLINder geometric object defined by Pt - the base *
- * 3d center point, Dir - the cylin direction and length, and base radius R. *
- * The second base is defined from first one by translating it by vector *
- * Dir, and its points are prefixed with T. *
- *****************************************************************************/
- struct ObjectStruct * GenCYLINObject(VectorType Pt, VectorType Dir, RealType *R)
- {
- int i, Resolution;
- RealType Angle, AngleStep;
- PointType LastCirclePt, CirclePt, TLastCirclePt, TCirclePt, TPt;
- MatrixType Mat;
- struct VertexStruct *VBase1, *VBase2 = NULL;
- struct PolygonStruct *PBase1, *PBase2;
- struct ObjectStruct *PCylin;
-
- Resolution = GetResolution(); /* Get refinement factor of object. */
-
- GenTransformMatrix(Mat, Pt, Dir, *R); /* Transform from unit circle. */
-
- PCylin = GenGeomObject("", NULL, NULL); /* Gen. the CYLIN object itself: */
- /* Also allocate the bases polygon header with first vertex on it: */
- PBase1 = AllocPolygon(0, 0, VBase1 = AllocVertex(0, 0, NULL, NULL), NULL);
- PBase2 = AllocPolygon(0, 0, VBase2 = AllocVertex(0, 0, NULL, NULL), NULL);
-
- PT_ADD(TPt, Pt, Dir); /* Translated circle center (by Dir). */
-
- LastCirclePt[0] = 1.0; /* First point is allways Angle = 0. */
- LastCirclePt[1] = 0.0;
- LastCirclePt[2] = 0.0;
- MatMultVecby4by4(LastCirclePt, LastCirclePt, Mat);
- PT_COPY(VBase1 -> Pt, LastCirclePt);/* Update first pt in base1 polygon. */
- PT_ADD(TLastCirclePt, LastCirclePt, Dir); /* Translated circle (by Dir). */
- PT_COPY(VBase2 -> Pt, TLastCirclePt);/* Update first pt in base2 polygon.*/
-
- AngleStep = M_PI * 2 / Resolution;
-
- for (i=1; i<=Resolution; 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);
- PT_ADD(TCirclePt, CirclePt, Dir); /* Translated circle (by Dir). */
-
- PCylin -> U.Pl = GenPolygon4Vrtx(TLastCirclePt, TCirclePt, CirclePt,
- LastCirclePt, Pt, PCylin -> U.Pl);
- /* 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 == Resolution) { /* Its last point - make it circular. */
- VBase1 -> Pnext = PBase1 -> V;
- VBase2 -> Pnext = PBase2 -> V;
- }
- else {
- VBase1 -> Pnext = AllocVertex(0, 0, NULL, NULL);
- VBase1 = VBase1 -> Pnext;
- PT_COPY(VBase1 -> Pt, CirclePt);
- PBase2 -> V = AllocVertex(0, 0, NULL, PBase2 -> V);
- PT_COPY(PBase2 -> V -> Pt, TCirclePt);
- }
-
- PT_COPY(LastCirclePt, CirclePt);/* Save pt in last pt for next time. */
- PT_COPY(TLastCirclePt, TCirclePt);
- }
-
- UpdatePolyPlane(PBase1, TPt); /* Update base polygon plane equation. */
- SET_CONVEX_POLY(PBase1); /* Mark it as convex polygon. */
- PBase1 -> Pnext = PCylin -> U.Pl; /* And stick it into cylin polygons. */
- PCylin -> U.Pl = PBase1;
- UpdatePolyPlane(PBase2, Pt); /* Update base polygon plane equation. */
- SET_CONVEX_POLY(PBase2); /* Mark it as convex polygon. */
- PBase2 -> Pnext = PCylin -> U.Pl; /* And stick it into cylin polygons. */
- PCylin -> U.Pl = PBase2;
-
- SET_OBJECT_COLOR(PCylin, PrimColor); /* Set its default color. */
-
- return PCylin;
- }
-
- /*****************************************************************************
- * Routine to create a SPHERE geometric object defined by Center - sphere *
- * 3d center point, and R its radius. *
- * Note polygons on the poles are triangles, while others are rectangles *
- * Teta is horizontal circle angle, Fee is the vertical (spherical coords.) *
- * The vertical axes here is assumed to be the Z axes. *
- *****************************************************************************/
- struct ObjectStruct * GenSPHEREObject(VectorType Center, RealType *R)
- {
- int i, j, Resolution;
- RealType TetaAngle, TetaAngleStep, FeeAngle, FeeAngleStep,
- CosFeeAngle1, SinFeeAngle1, CosFeeAngle2, SinFeeAngle2;
- PointType LastCircleLastPt, LastCirclePt, CirclePt, CircleLastPt;
- struct ObjectStruct *PSphere;
-
- Resolution = GetResolution(); /* Get refinement factor of object. */
-
- PSphere = GenGeomObject("", NULL, NULL);/* Gen the SPHERE object itself: */
-
- TetaAngleStep = M_PI * 2.0 / Resolution; /* Runs from 0 to 2*PI. */
- FeeAngleStep = M_PI * 2.0 / Resolution; /* 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<=Resolution; i++) { /* Pass the 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);
-
- PT_COPY(CircleLastPt, CirclePt);/* Save pt in last pt for next time. */
- }
-
- /* Generate the middle rectangular polygons: */
- for (i=1; i<Resolution/2-1; i++) { /* For all the horizontal circles do. */
- 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<=Resolution; j++) {/* Pass the whole (horizontal) 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);
-
- 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<=Resolution; i++) { /* Pass the 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);
-
- PT_COPY(CircleLastPt, CirclePt);/* Save pt in last pt for next time. */
- }
-
- SET_OBJECT_COLOR(PSphere, PrimColor); /* Set its default color. */
-
- return PSphere;
- }
-
- /*****************************************************************************
- * Routine to create a TORUS geometric object defined by Center - torus 3d *
- * center point, the main torus plane normal Normal, major radius Rmajor and *
- * minor radius Rminor (Tube radius). *
- * Teta runs on the major circle, Fee on the minor one (Before Mat trans.): *
- * X = (Rmajor + Rminor * cos(Fee)) * cos(Teta) *
- * Y = (Rmajor + Rminor * cos(Fee)) * sin(Teta) *
- * Z = Rminor * sin(Fee) *
- *****************************************************************************/
- struct ObjectStruct * GenTORUSObject(VectorType Center, VectorType Normal,
- RealType *Rmajor, RealType *Rminor)
- {
- int i, j, Resolution;
- RealType TetaAngle, TetaAngleStep, FeeAngle, FeeAngleStep,
- CosFeeAngle1, SinFeeAngle1, CosFeeAngle2, SinFeeAngle2;
- PointType LastCircleLastPt, LastCirclePt, CirclePt, CircleLastPt, InPt;
- MatrixType Mat;
- struct ObjectStruct *PTorus;
-
- Resolution = GetResolution(); /* Get refinement factor of object. */
-
- GenTransformMatrix(Mat, Center, Normal, 1.0); /* Trans from unit circle. */
-
- PTorus = GenGeomObject("", NULL, NULL); /* Gen. the Torus object itself: */
-
- TetaAngleStep = M_PI * 2.0 / Resolution; /* Runs from 0 to 2*PI. */
- FeeAngleStep = M_PI * 2.0 / Resolution; /* Runs from 0 to 2*PI. */
-
- for (i=1; i<=Resolution; 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);
-
- for (j=1; j<=Resolution; 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);
-
- PT_COPY(LastCirclePt, CirclePt); /* Save pt in last pt. */
- PT_COPY(LastCircleLastPt, CircleLastPt);
- }
- }
-
- SET_OBJECT_COLOR(PTorus, PrimColor); /* Set its default color. */
-
- return PTorus;
- }
-
- /*****************************************************************************
- * Routine to create a PLANE geometric object defined by the normal N and *
- * the translation vector T. The object is a FINITE plane (a circle of *
- * RESOLUTION point in it...) and its radius is equal to R. *
- * The normal direction is assumed to point to the inside of the object. *
- *****************************************************************************/
- struct ObjectStruct * GenPLANEObject(VectorType N, VectorType T, RealType *R)
- {
- int i, Resolution;
- RealType Angle, AngleStep;
- PointType CirclePt;
- MatrixType Mat;
- struct VertexStruct *V;
- struct PolygonStruct *PCirc;
- struct ObjectStruct *PPlane;
-
- Resolution = GetResolution(); /* Get refinement factor of object. */
-
- GenTransformMatrix(Mat, T, N, *R); /* Transform from unit circle. */
-
- PPlane = GenGeomObject("", NULL, NULL); /* Gen. the PLANE object itself: */
- PCirc = AllocPolygon(0, 0, V = AllocVertex(0, 0, NULL, NULL), NULL);
- PPlane -> 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 -> Pt, CirclePt); /* Update first pt in circle polygon. */
-
- AngleStep = M_PI * 2 / Resolution;
-
- for (i=1; i<=Resolution; 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 == Resolution) { /* Its last point - make it circular. */
- V -> Pnext = PCirc -> V;
- }
- else {
- V -> Pnext = AllocVertex(0, 0, NULL, NULL);
- V = V -> Pnext;
- PT_COPY(V -> Pt, CirclePt);
- }
- }
-
- PT_ADD(CirclePt, CirclePt, N); /* Make a point "IN" the circle object. */
- UpdatePolyPlane(PCirc, CirclePt); /* Update base polygon plane equation. */
- SET_CONVEX_POLY(PCirc); /* Mark it as convex polygon. */
-
- SET_OBJECT_COLOR(PPlane, PrimColor); /* Set its default color. */
-
- return PPlane;
- }
-
- /*****************************************************************************
- * Routine to create a POLYgon directly from its specifed vertices. *
- * The validity of list elements is tested to make sure they are vectors as *
- * nobody else checked it till now (lists can hold any object type!). *
- * No test is made to make sure all vertices are on one plane, and that no *
- * two vertices are similar. *
- *****************************************************************************/
- struct ObjectStruct *GenPOLYObject(ObjectStruct *PObjList)
- {
- int i, NumVertices = 0;
- VertexStruct *V, *VHead, *VTail;
- PolygonStruct *PPoly;
- ObjectStruct *PObj, *PObjPoly;
-
- if (!IS_OLST_OBJ(PObjList))
- FatalError("GenPOLYObject: Not object list object!\n");
-
- i = 0;
- while ((PObj = PObjList -> U.PObjList[i]) != NULL && i++ < MAX_OBJ_LIST) {
- if (!IS_VEC_OBJ(PObj)) {
- WndwInputWindowPutStr("POLY: None vector object found in list, empty object result.", RED);
- return NULL;
- }
- NumVertices++;
- }
-
- if (NumVertices < 3) {
- WndwInputWindowPutStr("POLY: Less than 3 vertices, empty object result.", RED);
- return NULL;
- }
-
- PPoly = AllocPolygon(0, 0, VHead = NULL, NULL);
- i = 0;
- while ((PObj = PObjList -> U.PObjList[i]) != NULL && i++ < MAX_OBJ_LIST) {
- V = AllocVertex(0, 0, NULL, NULL);
- PT_COPY(V -> Pt, PObj -> U.Vec);
- if (VHead == NULL)
- {
- PPoly -> V = VHead = VTail = V;
- }
- else
- {
- VTail -> Pnext = V;
- VTail = V;
- }
- }
- VTail -> Pnext = VHead; /* Close the vertex list loop. */
-
- CGPlaneFrom3Points(PPoly -> Plane, VHead -> Pt, VHead -> Pnext -> Pt,
- VHead -> Pnext -> Pnext -> Pt);
-
- PObjPoly = GenGeomObject("", NULL, NULL);/* Gen. the POLY object itself: */
- PObjPoly -> U.Pl = PPoly;
- SET_OBJECT_COLOR(PObjPoly, PrimColor); /* Set its default color. */
-
- return PObjPoly;
- }
-
- /*****************************************************************************
- * Routine to a cross section polygon, by interactively allowing the user *
- * to create it. This polygon is returned as a one polygon object. This *
- * polygon is mainly for Surface of Revolution (SURFREV) and extrusion *
- * (EXTRUDE) operations, although it may be used as an open object by itself. *
- *****************************************************************************/
- struct ObjectStruct * GenCROSSECObject(ObjectStruct *PObj)
- {
- if (PObj && !IS_GEOM_OBJ(PObj))
- FatalError("CrossSec: operation on none geometric object\n");
-
- WndwInputWindowPutStr("GenCrossSecObject not implemented", RED);
-
- return NULL;
- }
-
- /*****************************************************************************
- * Routine to a create surface of revolution by rotating the given cross *
- * section along Z axes. The polygon plane must not be perpendicular to Z. *
- *****************************************************************************/
- struct ObjectStruct * GenSURFREVObject(ObjectStruct *Cross)
- {
- int Resolution, i;
- MatrixType Mat; /* Rotation Matrix around Z axes. */
- VertexStruct *V1, *V1Head, *V2, *V2Head, *VIn, *VInHead;
- PolygonStruct *Pl1, *Pl2, *PlIn, *PlNew = NULL;
- ObjectStruct *PSurfRev;
-
- if (!IS_GEOM_OBJ(Cross))
- FatalError("SurfRev: cross section is not geometric object\n");
-
- if (APX_EQ(Cross -> U.Pl -> Plane[0], 0.0) &&
- APX_EQ(Cross -> U.Pl -> Plane[1], 0.0)) {
- WndwInputWindowPutStr("SurfRev: cross-section perpendicular to Z. Empty object result", RED);
- return NULL;
- }
-
- Pl1 = AllocPolygon(0, 0, V1Head = CopyVList(Cross -> U.Pl -> V), NULL);
- PLANE_COPY(Pl1 -> Plane, Cross -> U.Pl -> Plane);
- Pl2 = AllocPolygon(0, 0, V2Head = CopyVList(Cross -> U.Pl -> V), NULL);
- PLANE_COPY(Pl2 -> Plane, Cross -> U.Pl -> Plane);
- PlIn = GenInsidePoly(Pl1);
- VInHead = PlIn -> V;
- Resolution = GetResolution(); /* Get refinement factor of object. */
- MatGenMatRotZ1(2.0 * M_PI / Resolution, Mat);
-
- for (i=0; i<Resolution; i++)
- {
- V2 = V2Head;
- do {
- MatMultVecby4by4(V2 -> Pt, V2 -> Pt , Mat);
- V2 = V2 -> Pnext;
- }
- while (V2 != NULL && V2 != V2Head);
-
- V1 = V1Head;
- if (i < Resolution - 1) /* If this is the last loop use the original */
- V2 = V2Head; /* polygon as we might accumulate error during the */
- else V2 = Cross -> U.Pl -> V; /* transformations along the circle. */
- VIn = VInHead;
- do
- {
- PlNew = GenPolygon4Vrtx(V1 -> Pt, V1 -> Pnext -> Pt,
- V2 -> Pnext -> Pt, V2 -> Pt,
- VIn -> Pt, PlNew);
-
- VIn = VIn -> Pnext;
- V1 = V1 -> Pnext;
- V2 = V2 -> Pnext;
- }
- while (V1 -> Pnext != NULL && V1 != V1Head);
-
- V1 = V1Head;
- do {
- MatMultVecby4by4(V1 -> Pt, V1 -> Pt , Mat);
- V1 = V1 -> Pnext;
- }
- while (V1 != NULL && V1 != V1Head);
- VIn = VInHead;
- do {
- MatMultVecby4by4(VIn -> Pt, VIn -> Pt , Mat);
- VIn = VIn -> Pnext;
- }
- while (VIn != NULL && VIn != VInHead);
- }
-
- MyFree((char *) PlIn, POLYGON_TYPE);
- MyFree((char *) Pl1, POLYGON_TYPE);
- MyFree((char *) Pl2, POLYGON_TYPE);
-
- PSurfRev = GenGeomObject("", NULL, NULL);
- PSurfRev -> U.Pl = PlNew;
- SET_OBJECT_COLOR(PSurfRev, PrimColor); /* Set its default color. */
-
- return PSurfRev;
- }
-
- /*****************************************************************************
- * Routine to a create surface of extrusion out of the given cross section *
- * and the given direction. A NULL object will be returned, if the direction *
- * vector is in the cross section plane. *
- *****************************************************************************/
- struct ObjectStruct * GenEXTRUDEObject(ObjectStruct *Cross, VectorType Dir)
- {
- int i;
- RealType R;
- VertexStruct *V1, *V1Head, *V2, *VIn;
- PolygonStruct *PBase1, *PBase2, *Pl, *PlIn;
- ObjectStruct *PExtrude;
-
- if (!IS_GEOM_OBJ(Cross))
- FatalError("Extrude: cross section is not geometric object\n");
-
- R = DOT_PROD(Cross -> U.Pl -> Plane, Dir);
- if (APX_EQ(R, 0.0)) {
- WndwInputWindowPutStr("Extrusion direction in cross-section plane. Empty object result", RED);
- return NULL;
- }
-
- /* Prepare the two bases (update their plane normal to point INDISE): */
- PBase1 = AllocPolygon(0, 0, CopyVList(Cross -> U.Pl -> V), NULL);
- Pl = PBase2 = AllocPolygon(0, 0, CopyVList(Cross -> U.Pl -> V), PBase1);
- V1 = V1Head = PBase2 -> V;
- do {
- PT_ADD(V1 -> Pt, Dir, V1 -> Pt);
- 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 -> V -> Pt));
- }
- 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 -> V -> Pt));
- }
-
- /* Now generate all the 4 corner polygon between the two bases: */
- V1 = V1Head = PBase1 -> V;
- V2 = PBase2 -> V;
- PlIn = GenInsidePoly(PBase1);
- VIn = PlIn -> V;
- do {
- Pl = GenPolygon4Vrtx(V1 -> Pt, V1 -> Pnext -> Pt,
- V2 -> Pnext -> Pt, V2 -> Pt, VIn -> Pt, Pl);
- VIn = VIn -> Pnext;
- V1 = V1 -> Pnext;
- V2 = V2 -> Pnext;
- }
- while (V1 -> Pnext != NULL && V1 != V1Head);
-
- MyFree((char *) PlIn, POLYGON_TYPE);
-
- PExtrude = GenGeomObject("", NULL, NULL);
- PExtrude -> U.Pl = Pl;
- SET_OBJECT_COLOR(PExtrude, PrimColor); /* Set its default color. */
-
- return PExtrude;
- }
-
- /*****************************************************************************
- * 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. *
- *****************************************************************************/
- static struct PolygonStruct *GenInsidePoly(PolygonStruct *Pl)
- {
- int Axes;
- RealType Dx, Dy;
- PointType Pt;
- MatrixType Mat;
- PolygonStruct *PlIn;
- VertexStruct *VHead, *V, *Vnext, *VInHead, *VIn = NULL;
-
- PlIn = AllocPolygon(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);
- VHead = V = CopyVList(Pl -> V); /* We dont want to modify original! */
- Pl = AllocPolygon(0, 0, VHead, NULL);
- do {
- MatMultVecby4by4(V -> Pt, V -> Pt, Mat);
- V = V -> Pnext;
- }
- while (V != NULL && V != VHead);
-
- V = VHead;
- do {
- Vnext = V -> Pnext;
- Dx = ABS(V -> Pt[0] - Vnext -> Pt[0]);
- Dy = ABS(V -> Pt[1] - Vnext -> Pt[1]);
- Pt[0] = (V -> Pt[0] + Vnext -> Pt[0]) / 2.0;/* Prepare middle point. */
- Pt[1] = (V -> Pt[1] + Vnext -> Pt[1]) / 2.0;
- Pt[2] = V -> Pt[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 = AllocVertex(0, 0, NULL, NULL);
- VIn = VIn -> Pnext;
- }
- else {
- PlIn -> V = VInHead = VIn = AllocVertex(0, 0, NULL, NULL);
- }
- PT_COPY(VIn ->Pt, Pt);
-
- V = Vnext;
- }
- while (V != NULL && V != VHead);
- VIn -> Pnext = VInHead;
-
- MyFree((char *) Pl, POLYGON_TYPE);/* Free copied (and trans.) vrtx list. */
-
- /* Transform PlIn to the plane where original Pl is... */
- if (!MatInverseMatrix(Mat, Mat)) /* Find the inverse matrix. */
- FatalError("GenInsidePoly: Inverse matrix does not exits");
- VIn = VInHead;
- do {
- MatMultVecby4by4(VIn -> Pt, VIn -> Pt, Mat);
- VIn = VIn -> Pnext;
- }
- while (VIn != NULL && VIn != VInHead);
-
- return PlIn;
- }
-
- /*****************************************************************************
- * 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 normal direction can be evaluated uniquely. *
- * No test is made to make sure the 4 points are co-planar... *
- *****************************************************************************/
- static struct PolygonStruct *GenPolygon4Vrtx(VectorType V1, VectorType V2,
- VectorType V3, VectorType V4, VectorType Vin, PolygonStruct *Pnext)
- {
- struct PolygonStruct *PPoly;
- struct VertexStruct *V;
-
- PPoly = AllocPolygon(0, 0, V = AllocVertex(0, 0, NULL, NULL), Pnext);
- PT_COPY(V -> Pt, V1);
-
- V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Pt, V2);
-
- V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Pt, V3);
-
- V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Pt, V4);
-
- V -> Pnext = PPoly -> V; /* Make the Vertex list circular. */
-
- UpdatePolyPlane(PPoly, Vin); /* Update plane equation. */
-
- SET_CONVEX_POLY(PPoly); /* Mark it as convex polygon. */
-
- return PPoly;
- }
-
- /*****************************************************************************
- * Routine to create a polygon out of a list of 3 vertices V1/2/3 *
- * The forth 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 normal direction can be evaluated uniquely. *
- *****************************************************************************/
- static struct PolygonStruct *GenPolygon3Vrtx(VectorType V1, VectorType V2,
- VectorType V3, VectorType Vin, PolygonStruct *Pnext)
- {
- struct PolygonStruct *PPoly;
- struct VertexStruct *V;
-
- PPoly = AllocPolygon(0, 0, V = AllocVertex(0, 0, NULL, NULL), Pnext);
- PT_COPY(V -> Pt, V1);
-
- V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Pt, V2);
-
- V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Pt, V3);
-
- V -> Pnext = PPoly -> V; /* Make the Vertex list circular. */
-
- UpdatePolyPlane(PPoly, Vin); /* Update plane equation. */
-
- SET_CONVEX_POLY(PPoly); /* Mark it as convex polygon. */
-
- return PPoly;
- }
-
- /*****************************************************************************
- * Routine to preper transformation martix to do the following (in this *
- * order): scale by Scale, rotate such that the Z axis is in direction Dir *
- * and then translate by Trans. *
- * Algorithm: given the Trans vector, it forms the 4th line of Mat. Dir is *
- * used to form the second line (the first 3 lines set the rotation), and *
- * finally Scale is used to scale first 3 lines/columns to the needed scale: *
- * | Tx Ty Tz 0 | A transformation which takes the coord *
- * | Bx By Bz 0 | system into T, N & B as required and *
- * [X Y Z 1] * | Nx Ny Nz 0 | then translate it to C. T, N, B are *
- * | Cx Cy Cz 1 | scaled by Scale. *
- * N is exactly Dir (unit vec) but we got freedom on T & B - T & B must be on *
- * a plane perpendicular to N and perpendicular between them but thats all! *
- * T is therefore selected using this (heuristic ?) algorithm: *
- * Let P be the axis of which the absolute N coefficient is the smallest. *
- * Let B be (N cross P) and T be (B cross N). *
- *****************************************************************************/
- static void GenTransformMatrix(MatrixType Mat, VectorType Trans,
- VectorType Dir, RealType Scale)
- {
- int i, j;
- RealType R;
- VectorType DirN, T, B, P;
- MatrixType TempMat;
-
- PT_COPY(DirN, Dir);
- PT_NORMALIZE(DirN);
- PT_CLEAR(P);
- for (i=1, j=0, R = ABS(DirN[0]); i<3; i++) if (R > ABS(DirN[i])) {
- R = DirN[i];
- j = i;
- }
- P[j] = 1.0;/* Now P is set to the axis with the biggest angle from DirN. */
-
- VecCrossProd(B, DirN, P); /* Calc the bi-normal. */
- VecCrossProd(T, B, DirN); /* Calc the tangent. */
-
- MatGenUnitMat(Mat);
- for (i=0; i<3; i++) {
- Mat[0][i] = T[i];
- Mat[1][i] = B[i];
- Mat[2][i] = DirN[i];
- }
- MatGenMatScale(Scale, Scale, Scale, TempMat);
- MatMultTwo4by4(Mat, TempMat, Mat);
-
- MatGenMatTrans(Trans[0], Trans[1], Trans[2], TempMat);
- MatMultTwo4by4(Mat, Mat, TempMat);
- }
-
- /*****************************************************************************
- * Routine to update the Plane equation of the given polygon such that the *
- * Vin vertex will be in the positive side of it. *
- * It is assumed the polygon has at list 3 points... *
- *****************************************************************************/
- void UpdatePolyPlane(PolygonStruct *PPoly, VectorType Vin)
- {
- int i;
- VectorType V1, V2;
- RealType Len;
- struct VertexStruct *V;
-
- V = PPoly -> V; PT_SUB(V1, V -> Pt, V -> Pnext -> Pt);
- V = V -> Pnext; PT_SUB(V2, V -> Pt, V -> Pnext -> Pt);
-
- VecCrossProd(PPoly -> Plane, V1, V2); /* Find Plane Normal. */
- /* Normalize the plane such that the normal has length of 1: */
- Len = PT_LENGTH(PPoly -> Plane);
- for (i=0; i<3; i++) PPoly -> Plane[i] /= Len;
-
- PPoly -> Plane[3] = (-DOT_PROD(PPoly -> Plane, PPoly -> V -> Pt));
-
- if (DOT_PROD(PPoly -> Plane, Vin) + PPoly -> Plane[3] < 0) {
- /* Flip plane normal and reverse the vertex list. */
- ReverseVrtxList(PPoly);
- for (i=0; i<4; i++) PPoly -> Plane[i] = (-PPoly -> Plane[i]);
- }
- }
-