home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega CD-ROM 1
/
megacd_rom_1.zip
/
megacd_rom_1
/
IRIT
/
IRITS.ZIP
/
GEOMAT3D.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-05
|
30KB
|
798 lines
/*****************************************************************************
* "Irit" - the 3d polygonal solid modeller. *
* *
* Written by: Gershon Elber Ver 0.2, Mar. 1990 *
******************************************************************************
* Routines to generate transformation matrices for Translation, Rotation *
* and Scaling for 3D universe. *
* Routines to manipulate 3D vectors. *
* And some computational geometry routines. *
*****************************************************************************/
#include <math.h>
#include <stdio.h>
#include "program.h"
#include "objects.h"
#include "geomat3d.h"
#include "primitvg.h"
/* #define DEBUG Print information on entry and exit of routines. */
static int CGPointRayRelation(PointType Pt, PointType PtRay, int Axes);
/*****************************************************************************
* Routine to generate a 4*4 unit matrix: *
*****************************************************************************/
void MatGenUnitMat(MatrixType Mat)
{
int i, j;
for (i=0; i<4; i++) for (j=0; j<4; j++)
if (i==j) Mat[i][j] = 1.0;
else Mat[i][j] = 0.0;
}
/*****************************************************************************
* Routine to generate a 4*4 matrix to translate in Tx, Ty, Tz amounts. *
*****************************************************************************/
void MatGenMatTrans(RealType Tx, RealType Ty, RealType Tz, MatrixType Mat)
{
MatGenUnitMat(Mat); /* Make it unit matrix. */
Mat[3][0] = Tx;
Mat[3][1] = Ty;
Mat[3][2] = Tz;
}
/*****************************************************************************
* Routine to generate a 4*4 matrix to Scale x, y, z in Sx, Sy, Sz amounts. *
*****************************************************************************/
void MatGenMatScale(RealType Sx, RealType Sy, RealType Sz, MatrixType Mat)
{
MatGenUnitMat(Mat); /* Make it unit matrix. */
Mat[0][0] = Sx;
Mat[1][1] = Sy;
Mat[2][2] = Sz;
}
/*****************************************************************************
* Routine to generate a 4*4 matrix to Rotate around X with angle of Teta. *
* Note Teta must be given in radians. *
*****************************************************************************/
void MatGenMatRotX1(RealType Teta, MatrixType Mat)
{
RealType CTeta, STeta;
CTeta = (RealType) cos((double) Teta);
STeta = (RealType) sin((double) Teta);
MatGenMatRotX(CTeta, STeta, Mat);
}
/*****************************************************************************
* Routine to generate a 4*4 matrix to Rotate around X with angle of Teta. *
*****************************************************************************/
void MatGenMatRotX(RealType CosTeta, RealType SinTeta, MatrixType Mat)
{
MatGenUnitMat(Mat); /* Make it unit matrix. */
Mat[1][1] = CosTeta;
Mat[1][2] = SinTeta;
Mat[2][1] = -SinTeta;
Mat[2][2] = CosTeta;
}
/*****************************************************************************
* Routine to generate a 4*4 matrix to Rotate around Y with angle of Teta. *
* Note Teta must be given in radians. *
*****************************************************************************/
void MatGenMatRotY1(RealType Teta, MatrixType Mat)
{
RealType CTeta, STeta;
CTeta = (RealType) cos((double) Teta);
STeta = (RealType) sin((double) Teta);
MatGenMatRotY(CTeta, STeta, Mat);
}
/*****************************************************************************
* Routine to generate a 4*4 matrix to Rotate around Y with angle of Teta. *
*****************************************************************************/
void MatGenMatRotY(RealType CosTeta, RealType SinTeta, MatrixType Mat)
{
MatGenUnitMat(Mat); /* Make it unit matrix. */
Mat[0][0] = CosTeta;
Mat[0][2] = -SinTeta;
Mat[2][0] = SinTeta;
Mat[2][2] = CosTeta;
}
/*****************************************************************************
* Routine to generate a 4*4 matrix to Rotate around Z with angle of Teta. *
* Note Teta must be given in radians. *
*****************************************************************************/
void MatGenMatRotZ1(RealType Teta, MatrixType Mat)
{
RealType CTeta, STeta;
CTeta = (RealType) cos((double) Teta);
STeta = (RealType) sin((double) Teta);
MatGenMatRotZ(CTeta, STeta, Mat);
}
/*****************************************************************************
* Routine to generate a 4*4 matrix to Rotate around Z with angle of Teta. *
*****************************************************************************/
void MatGenMatRotZ(RealType CosTeta, RealType SinTeta, MatrixType Mat)
{
MatGenUnitMat(Mat); /* Make it unit matrix, */
Mat[0][0] = CosTeta;
Mat[0][1] = SinTeta;
Mat[1][0] = -SinTeta;
Mat[1][1] = CosTeta;
}
/*****************************************************************************
* Routine to multiply 2 4by4 matrices: *
* Note MatRes might be one of Mat1 or Mat2 - it is only updated in the end! *
*****************************************************************************/
void MatMultTwo4by4(MatrixType MatRes, MatrixType Mat1, MatrixType Mat2)
{
int i, j, k;
MatrixType MatResTemp;
for (i=0; i<4; i++) for (j=0; j<4; j++) {
MatResTemp[i][j] = 0;
for (k=0; k<4; k++) MatResTemp[i][j] += Mat1[i][k] * Mat2[k][j];
}
for (i=0; i<4; i++) for (j=0; j<4; j++) MatRes[i][j] = MatResTemp[i][j];
}
/*****************************************************************************
* Routine to add 2 4by4 matrices: *
* Note MatRes might be one of Mat1 or Mat2. *
*****************************************************************************/
void MatAddTwo4by4(MatrixType MatRes, MatrixType Mat1, MatrixType Mat2)
{
int i, j;
for (i=0; i<4; i++) for (j=0; j<4; j++)
MatRes[i][j] = Mat1[i][j] + Mat2[i][j];
}
/*****************************************************************************
* Routine to subtract 2 4by4 matrices: *
* Note MatRes might be one of Mat1 or Mat2. *
*****************************************************************************/
void MatSubTwo4by4(MatrixType MatRes, MatrixType Mat1, MatrixType Mat2)
{
int i, j;
for (i=0; i<4; i++) for (j=0; j<4; j++)
MatRes[i][j] = Mat1[i][j] - Mat2[i][j];
}
/*****************************************************************************
* Routine to scale a 4by4 matrix by constant: *
* Note MatRes might be Mat. *
*****************************************************************************/
void MatScale4by4(MatrixType MatRes, MatrixType Mat, RealType *Scale)
{
int i, j;
for (i=0; i<4; i++) for (j=0; j<4; j++)
MatRes[i][j] = Mat[i][j] * (*Scale);
}
/*****************************************************************************
* Routine to multiply Vector by 4by4 matrix: *
* The Vector has only 3 components (X, Y, Z) and it is assumed that W = 1 *
* Note VRes might be Vec as it is only updated in the end. *
*****************************************************************************/
void MatMultVecby4by4(VectorType VRes, VectorType Vec, MatrixType Mat)
{
int i, j;
RealType CalcW = Mat[3][3];
VectorType VTemp;
for (i=0; i<3; i++) {
VTemp[i] = Mat[3][i]; /* Initiate it with the weight factor. */
for (j=0; j<3; j++) VTemp[i] += Vec[j] * Mat[j][i];
}
for (i=0; i<3; i++) CalcW += Vec[i] * Mat[i][3];
if (CalcW == 0) CalcW = 1/INFINITY;
for (i=0; i<3; i++) VRes[i] = VTemp[i]/CalcW;
}
/*****************************************************************************
* Procedure to calculate the INVERSE of a given matrix M which is not *
* modified. The matrix is assumed to be 4 by 4 (transformation matrix). *
* Return TRUE if inverted matrix (InvM) do exists. *
*****************************************************************************/
int MatInverseMatrix(MatrixType M, MatrixType InvM)
{
MatrixType A;
int i, j, k;
RealType V;
MAT_COPY(A, M); /* Prepare temporary copy of M in A. */
MatGenUnitMat(InvM); /* Make it unit matrix. */
for (i=0; i<4; i++) {
V = A[i][i]; /* Find the new pivot. */
k = i;
for (j=i+1; j<4; j++) if (ABS(A[j][i]) > ABS(V)) {
/* Find maximum on col i, row i+1..n */
V = A[j][i];
k = j;
}
j = k;
if (i != j) for (k=0; k<4; k++) {
SWAP(A[i][k], A[j][k], RealType);
SWAP(InvM[i][k], InvM[j][k], RealType);
}
for (j=i+1; j<4; j++) { /* Eliminate col i from row i+1..n. */
V = A[j][i] / A[i][i];
for (k=0; k<4; k++) {
A[j][k] -= V * A[i][k];
InvM[j][k] -= V * InvM[i][k];
}
}
}
for (i=3; i>=0; i--) { /* Back Substitution. */
if (A[i][i] == 0) return FALSE; /* Error. */
for (j=0; j<i; j++) { /* Eliminate col i from row 1..i-1. */
V = A[j][i] / A[i][i];
for (k=0; k<4; k++) {
/* A[j][k] -= V * A[i][k]; */
InvM[j][k] -= V * InvM[i][k];
}
}
}
for (i=0; i<4; i++) /* Normalize the inverse Matrix. */
for (j=0; j<4; j++)
InvM[i][j] /= A[i][i];
return TRUE;
}
/*****************************************************************************
* Routine to copy one vector to another: *
*****************************************************************************/
void VecCopy(VectorType Vdst, VectorType Vsrc)
{
int i;
for (i=0; i<3; i++) Vdst[i] = Vsrc[i];
}
/*****************************************************************************
* Routine to normalize the vector length to a unit length: *
*****************************************************************************/
void VecNormalize(VectorType V)
{
int i;
RealType Len;
Len = VecLength(V);
if (Len > 0.0) for (i=0; i<3; i++) {
V[i] /= Len;
if (ABS(V[i]) < EPSILON) V[i] = 0.0;
}
}
/*****************************************************************************
* Routine to calculate the magnitude (length) of a given 3D vector: *
*****************************************************************************/
RealType VecLength(VectorType V)
{
return sqrt(SQR(V[0]) + SQR(V[1]) + SQR(V[2]));
}
/*****************************************************************************
* Routine to calculate the cross product of two vectors: *
* Note Vres might be the same as V1 or V2 ! *
*****************************************************************************/
void VecCrossProd(VectorType Vres, VectorType V1, VectorType V2)
{
VectorType Vtemp;
Vtemp[0] = V1[1] * V2[2] - V2[1] * V1[2];
Vtemp[1] = V1[2] * V2[0] - V2[2] * V1[0];
Vtemp[2] = V1[0] * V2[1] - V2[0] * V1[1];
VecCopy(Vres, Vtemp);
}
/*****************************************************************************
* Routine to calculate the dot product of two vectors: *
*****************************************************************************/
RealType VecDotProd(VectorType V1, VectorType V2)
{
return V1[0] * V2[0] + V1[1] * V2[1] + V1[2] * V2[2];
}
/*****************************************************************************
* Routine to generate rotation object around the X axis in Degree degrees: *
*****************************************************************************/
struct ObjectStruct *GenMatObjectRotX(RealType *Degree)
{
MatrixType Mat;
MatGenMatRotX1(DEG2RAD(*Degree), Mat); /* Generate the trans. matrix. */
return GenMatObject("", Mat, NULL);
}
/*****************************************************************************
* Routine to generate rotation object around the Y axis in Degree degrees: *
*****************************************************************************/
struct ObjectStruct *GenMatObjectRotY(RealType *Degree)
{
MatrixType Mat;
MatGenMatRotY1(DEG2RAD(*Degree), Mat); /* Generate the trans. matrix. */
return GenMatObject("", Mat, NULL);
}
/*****************************************************************************
* Routine to generate rotation object around the Z axis in Degree degrees: *
*****************************************************************************/
struct ObjectStruct *GenMatObjectRotZ(RealType *Degree)
{
MatrixType Mat;
MatGenMatRotZ1(DEG2RAD(*Degree), Mat); /* Generate the trans. matrix. */
return GenMatObject("", Mat, NULL);
}
/*****************************************************************************
* Routine to generate translation object according to XYZ vector Vec. *
*****************************************************************************/
struct ObjectStruct * GenMatObjectTrans(VectorType Vec)
{
MatrixType Mat;
/* Generate the transformation matrix */
MatGenMatTrans(Vec[0], Vec[1], Vec[2], Mat);
return GenMatObject("", Mat, NULL);
}
/*****************************************************************************
* Routine to scale an object according to XYZ scaling vector Vec. *
*****************************************************************************/
struct ObjectStruct * GenMatObjectScale(VectorType Vec)
{
MatrixType Mat;
/* Generate the transformation matrix */
MatGenMatScale(Vec[0], Vec[1], Vec[2], Mat);
return GenMatObject("", Mat, NULL);
}
/*****************************************************************************
* Routine to transform an object according to the transformation matrix. *
*****************************************************************************/
struct ObjectStruct *TransformObject(ObjectStruct *PObj, MatrixType Mat)
{
VectorType Pin;
struct PolygonStruct *Pl = PObj -> U.Pl;
struct VertexStruct *V, *VFirst;
if (!IS_GEOM_OBJ(PObj))
FatalError("TransfromObject: object is not geometric\n");
while (Pl != NULL) {
V = VFirst = Pl -> V;
PT_ADD(Pin, V -> Pt, Pl -> Plane); /* Prepare point in the IN side. */
MatMultVecby4by4(Pin, Pin, Mat); /* transformed relative to new pos. */
do {
MatMultVecby4by4(V -> Pt, V -> Pt, Mat);
V = V -> Pnext;
}
while (V != VFirst && V != NULL); /* VList is circular! */
if (!IS_POLYLINE_GEOM_OBJ(PObj))
UpdatePolyPlane(Pl, Pin); /* Update plane eqn. using IN point. */
Pl = Pl -> Pnext;
}
return PObj;
}
/*****************************************************************************
* Routine to calc the distance between two 3d points *
*****************************************************************************/
RealType CGDistPointPoint(PointType P1, PointType P2)
{
RealType t;
#ifdef DEBUG
printf("CGDistPointPoint entered\n");
#endif /* DEBUG */
t = sqrt(SQR(P2[0]-P1[0]) + SQR(P2[1]-P1[1]) + SQR(P2[2]-P1[2]));
#ifdef DEBUG
printf("CGDistPointPoint exit\n");
#endif /* DEBUG */
return t;
}
/*****************************************************************************
* Routine to create the plane from given 3 points. if two of the points *
* are the same it returns FALSE, otherwise (succesfull) returns TRUE. *
*****************************************************************************/
int CGPlaneFrom3Points(PlaneType Plane, PointType Pt1, PointType Pt2,
PointType Pt3)
{
VectorType V1, V2;
#ifdef DEBUG
printf("CGPlaneFrom3Points entered\n");
#endif /* DEBUG */
if (PT_EQ(Pt1, Pt2) || PT_EQ(Pt2, Pt3) || PT_EQ(Pt1, Pt3)) return FALSE;
PT_SUB(V1, Pt2, Pt1);
PT_SUB(V2, Pt3, Pt2);
VecCrossProd(Plane, V1, V2);
PT_NORMALIZE(Plane);
Plane[3] = -DOT_PROD(Plane, Pt1);
#ifdef DEBUG
printf("CGPlaneFrom3Points exit\n");
#endif /* DEBUG */
return TRUE;
}
/*****************************************************************************
* Routine to calc the closest 3d point to a given 3d line. the line is *
* given as a point on it (Pl) and vector (Vl). *
*****************************************************************************/
void CGPointFromPointLine(PointType Point, PointType Pl, PointType Vl,
PointType ClosestPoint)
{
int i;
PointType V1, V2;
RealType CosAlfa, VecMag;
#ifdef DEBUG
printf("CGPointFromLinePlane entered\n");
#endif /* DEBUG */
for (i=0; i<3; i++) {
V1[i] = Point[i] - Pl[i];
V2[i] = Vl[i];
}
VecMag = VecLength(V1);
VecNormalize(V1); /* Normalized vector from Point to a point on line Pl. */
VecNormalize(V2); /* Normalized line direction vector. */
CosAlfa = VecDotProd(V1, V2); /* Find the angle between the two vectors. */
/* Find P1 - the closest point to Point on the line: */
for (i=0; i<3; i++) ClosestPoint[i] = Pl[i] + V2[i] * CosAlfa * VecMag;
#ifdef DEBUG
printf("CGPointFromLinePlane exit\n");
#endif /* DEBUG */
}
/*****************************************************************************
* Routine to calc the distance between 3d point and 3d line. the line is *
* given as a point on it (Pl) and vector (Vl). *
*****************************************************************************/
RealType CGDistPointLine(PointType Point, PointType Pl, PointType Vl)
{
RealType t;
PointType Ptemp;
#ifdef DEBUG
printf("CGDistPointLine entered\n");
#endif /* DEBUG */
CGPointFromPointLine(Point, Pl, Vl, Ptemp);/* Find closest point on line.*/
t = CGDistPointPoint(Point, Ptemp);
#ifdef DEBUG
printf("CGDistPointLine exit\n");
#endif /* DEBUG */
return t;
}
/*****************************************************************************
* Routine to calc the distance between a Point and a Plane. The Plane is *
* defined with 4 coef. : Ax + By + Cz + D = 0 given as 4 elements vector. *
*****************************************************************************/
RealType CGDistPointPlane(PointType Point, PlaneType Plane)
{
RealType t;
#ifdef DEBUG
printf("CGDistPointPlane entered\n");
#endif /* DEBUG */
t = ((Plane[0] * Point [0] +
Plane[1] * Point [1] +
Plane[2] * Point [2] +
Plane[3]) /
sqrt(SQR(Plane[0]) + SQR(Plane[1]) + SQR(Plane[2])));
#ifdef DEBUG
printf("CGDistPointPlane exit\n");
#endif /* DEBUG */
return t;
}
/*****************************************************************************
* Routine to find the intersection point of a line and a plane (if any) *
* The Plane is defined with 4 coef. : Ax + By + Cz + D = 0 given as 4 *
* elements vector. The line is define via a point on it Pl and a direction *
* vector Vl. Return TRUE only if such point exists. *
*****************************************************************************/
int CGPointFromLinePlane(PointType Pl, PointType Vl, PlaneType Plane,
PointType InterPoint, RealType *t)
{
int i;
RealType DotProd;
#ifdef DEBUG
printf("CGPointFromLinePlane entered\n");
#endif /* DEBUG */
/* Check to see if they are vertical - no intersection at all! */
DotProd = VecDotProd(Vl, Plane);
if (ABS(DotProd) < EPSILON) return FALSE;
/* Else find t in line such that the plane equation plane is satisfied: */
*t = (-Plane[3] - Plane[0] * Pl[0] - Plane[1] * Pl[1] - Plane[2] * Pl[2])
/ DotProd;
/* And so find the intersection point which is at that t: */
for (i=0; i<3; i++) InterPoint[i] = Pl[i] + *t * Vl[i];
#ifdef DEBUG
printf("CGPointFromLinePlane exit\n");
#endif /* DEBUG */
return TRUE;
}
/*****************************************************************************
* Routine to find the intersection point of a line and a plane (if any) *
* The Plane is defined with 4 coef. : Ax + By + Cz + D = 0 given as 4 *
* elements vector. The line is define via a point on it Pl and a direction *
* vector Vl: Line == Pl + Vl * t, where t is the line parameter. *
* Return TRUE only if such point exists, in the t parameter range [0..1]. *
*****************************************************************************/
int CGPointFromLinePlane01(PointType Pl, PointType Vl, PlaneType Plane,
PointType InterPoint, RealType *t)
{
int i;
RealType DotProd;
#ifdef DEBUG
printf("CGPointFromLinePlane01 entered\n");
#endif /* DEBUG */
/* Check to see if they are vertical - no intersection at all! */
DotProd = VecDotProd(Vl, Plane);
if (ABS(DotProd) < EPSILON) return FALSE;
/* Else find t in line such that the plane equation plane is satisfied: */
*t = (-Plane[3] - Plane[0] * Pl[0] - Plane[1] * Pl[1] - Plane[2] * Pl[2])
/ DotProd;
if ((*t < 0.0 && !APX_EQ(*t, 0.0)) || /* Not in parameter range. */
(*t > 1.0 && !APX_EQ(*t, 1.0))) return FALSE;
/* And so find the intersection point which is at that t : */
for (i=0; i<3; i++) InterPoint[i] = Pl[i] + *t * Vl[i];
#ifdef DEBUG
printf("CGPointFromLinePlane01 exit\n");
#endif /* DEBUG */
return TRUE;
}
/*****************************************************************************
* Routine to find the two point Pti on the lines (Pli, Vli) , i = 1, 2 *
* with the minimal euclidian distance between them. In other words the *
* distance between Pt1 and Pt2 is defined as distance between the two lines. *
* The two points are calculated using the fact that if V = (Vl1 cross Vl2) *
* then these two points are the intersection point between the following: *
* point 1 - a plane (defined by V and line1) and the line line2. *
* point 2 - a plane (defined by V and line2) and the line line1. *
* This function returns TRUE iff the two lines are not parallel! *
*****************************************************************************/
int CG2PointsFromLineLine(PointType Pl1, PointType Vl1,
PointType Pl2, PointType Vl2,
PointType Pt1, RealType *t1,
PointType Pt2, RealType *t2)
{
int i;
PointType Vtemp;
PlaneType Plane1, Plane2;
#ifdef DEBUG
printf("CG2PointsFromLineLine entered\n");
#endif /* DEBUG */
VecCrossProd(Vtemp, Vl1, Vl2); /* Check to see if they are parallel. */
if (VecLength(Vtemp) < EPSILON) {
for (i=0; i<3; i++) Pt1[i] = Pl1[i]; /* Pick point on line1 and find */
CGPointFromPointLine(Pl1, Pl2, Vl2, Pt2); /* closest point on line2. */
return FALSE;
}
/* Define the two planes: 1) Vl1, Pl1, Vtemp and 2) Vl2, Pl2, Vtemp */
/* Note this sets the first 3 elements A, B, C out of the 4... */
VecCrossProd(Plane1, Vl1, Vtemp); /* Find the A, B, C coef.'s. */
VecNormalize(Plane1);
VecCrossProd(Plane2, Vl2, Vtemp); /* Find the A, B, C coef.'s. */
VecNormalize(Plane2);
/* and now use a point on the plane to find the 4th coef. D: */
Plane1[3] = (-VecDotProd(Plane1, Pl1)); /* Note VecDotProd uses only the */
Plane2[3] = (-VecDotProd(Plane2, Pl2)); /* first three elements in vec. */
/* Thats it! now we should solve for the intersection point between a */
/* line and a plane but we already familiar with this problem... */
i = CGPointFromLinePlane(Pl1, Vl1, Plane2, Pt1, t1) &&
CGPointFromLinePlane(Pl2, Vl2, Plane1, Pt2, t2);
#ifdef DEBUG
printf("CG2PointsFromLineLine exit\n");
#endif /* DEBUG */
return i;
}
/*****************************************************************************
* Routine to find the distance between two lines (Pli, Vli) , i = 1, 2. *
*****************************************************************************/
RealType CGDistLineLine(PointType Pl1, PointType Vl1,
PointType Pl2, PointType Vl2)
{
RealType t1, t2;
PointType Ptemp1, Ptemp2;
#ifdef DEBUG
printf("CGDistLineLine entered\n");
#endif /* DEBUG */
CG2PointsFromLineLine(Pl1, Vl1, Pl2, Vl2, Ptemp1, &t1, Ptemp2, &t2);
t1 = CGDistPointPoint(Ptemp1, Ptemp2);
#ifdef DEBUG
printf("CGDistLineLine exit\n");
#endif /* DEBUG */
return t1;
}
/*****************************************************************************
* Routine implements Jordan Theorem: Fire a ray from a given point and find*
* number of intersections of ray with the polygon, excluding the given point *
* Pt (start of ray) itself, if on polygon boundary. The ray is fired in +X *
* (Axes == 0) or +Y (Axes == 1). And only the X/Y coordinates of the polygon *
* are taken into account, i.e. the orthogonal projection of the polygon on *
* a X/Y parallel plane (equal to polygon itself if on X/Y parallel plane...) *
* Note that if the point is on polygon boundary, the ray should not be in *
* its edge direction *
* *
* Algorithm: *
* 1. Set NumOfIntersection = 0; *
* Find vertex V not on Ray level and set AlgState to its level (below or *
* above the ray level). If none goto 3 *
* Mark VStart = V; *
* 2. 2.1. While State(V) == AlgState do *
* 2.1.1. V = V -> Pnext; *
* 2.1.2. If V == VStart goto 3 *
* end; *
* IntersectionMinX = INFINITY; *
* 2.2. While State(V) == ON_RAY do *
* IntersectionMin = MIN(IntersectionMin, V -> Pt[Axes]); *
* V = V -> Pnext; *
* end; *
* 2.3. If State(V) != AlgState do *
* 2.3.1. Find the intersection point between polygon edge *
* Vlast, V and the Ray and update IntersectionMin if *
* lower than it. *
* 2.3.2. If IntersectionMin is greater than Pt[Axes] increase *
* the NumOfIntersection counter by 1. *
* end; *
* 2.4. AlgState = State(V); *
* 2.5. goto 2.1. *
* 3. return NumOfIntersection; *
* *
*****************************************************************************/
int CGPolygonRayInter(PolygonStruct *Pl, PointType PtRay, int RayAxes)
{
int NewState, AlgState, RayOtherAxes, NumOfInter = 0, Quit = FALSE;
RealType InterMin, Inter, t;
VertexStruct *V, *VStart, *VLast;
RayOtherAxes = (RayAxes == 1 ? 0 : 1); /* Other dir: X -> Y, Y -> X. */
/* Stage 1 - find a vertex below the ray level: */
V = VStart = Pl -> V;
do {
if ((AlgState = CGPointRayRelation(V -> Pt, PtRay, RayOtherAxes))
!= ON_RAY) break;
V = V -> Pnext;
}
while (V != VStart && V != NULL);
if (AlgState == ON_RAY) return 0;
VStart = V; /* Vertex Below Ray level */
/* Stage 2 - scan the vertices and count number of intersections. */
while (!Quit) {
/* Stage 2.1. : */
while (CGPointRayRelation(V -> Pt, PtRay, RayOtherAxes) == AlgState) {
VLast = V;
V = V -> Pnext;
if (V == VStart) {
Quit = TRUE;
break;
}
}
InterMin = INFINITY;
/* Stage 2.2. : */
while (CGPointRayRelation(V -> Pt, PtRay, RayOtherAxes) == ON_RAY) {
InterMin = MIN(InterMin, V -> Pt[RayAxes]);
VLast = V;
V = V -> Pnext;
if (V == VStart) Quit = TRUE;
}
/* Stage 2.3. : */
if ((NewState = CGPointRayRelation(V -> Pt, PtRay, RayOtherAxes))
!= AlgState) {
/* Stage 2.3.1 Intersection with ray is in middle of edge: */
t = (PtRay[RayOtherAxes] - V -> Pt[RayOtherAxes]) /
(VLast -> Pt[RayOtherAxes] - V -> Pt[RayOtherAxes]);
Inter = VLast -> Pt[RayAxes] * t + V -> Pt[RayAxes] * (1.0 - t);
InterMin = MIN(InterMin, Inter);
/* Stage 2.3.2. comp. with ray base and inc. # of inter if above.*/
if (InterMin > PtRay[RayAxes] &&
!APX_EQ(InterMin, PtRay[RayAxes])) NumOfInter++;
}
AlgState = NewState;
}
return NumOfInter;
}
/*****************************************************************************
* Routine to return the relation between the ray level and a given point, *
* to be used in the CGPolygonRayInter routine above. *
*****************************************************************************/
static int CGPointRayRelation(PointType Pt, PointType PtRay, int Axes)
{
if (APX_EQ(PtRay[Axes], Pt[Axes])) return ON_RAY;
else if (PtRay[Axes] < Pt[Axes]) return ABOVE_RAY;
else return BELOW_RAY;
}