home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * Routines to test all edges for visibility relative to the global polygon *
- * list, and output the visible ones, to graphics screen or as text file *
- * *
- * Written by: Gershon Elber Ver 2.0, Jan. 1989 *
- *****************************************************************************/
-
- #ifdef __MSDOS__
- #include <conio.h>
- #endif /* __MSDOS__ */
-
- #include <stdio.h>
- #include <math.h>
- #include <setjmp.h>
- #include <time.h>
- #include "program.h"
- #include "genmat.h"
- #include "parser.h"
-
- static struct EdgeStruct *OutEdgeHashTable[EDGE_HASH_TABLE_SIZE];
-
- static void OutputEdge(EdgeStruct *PEtemp);
- static int EmitOutEdgeHashTable(void);
- static struct EdgeStruct *FoundMatchEdge(int *Colinear, EdgeStruct *PEdge);
- static int FuzzSamePoints(float Pt1[3], float Pt2[3]);
- static int ColinearPoints(float Pt1[3], float Pt2[3], float Pt3[3]);
- static int VisibleEdge(int EdgeMinY, EdgeStruct *PEdge,
- PolygonStruct *PolyHashTable[]);
- static int VisibleEdgeOnePoly(EdgeStruct *PEdge, PolygonStruct *PPoly);
- static int InverseMatrix(MatrixType A);
- static void SwapDouble(double *D1, double *D2);
-
- /*****************************************************************************
- * Routine to test for visibility all edges in EdgeHashTable and display or *
- * output the visible ones only. It is assumed that only totally visible or *
- * invisible edges are in table (Pass 3 broke all other kind of edges). *
- *****************************************************************************/
- void OutVisibleEdges(void)
- {
- int i, PolyLineCount = 0;
- long SaveTime = time(NULL);
- struct EdgeStruct *PEtemp, *PEtail;
-
- fprintf(stderr, "\nPass 4, Edges [%5d] = ", EdgeCount);
- for (i=0; i<EDGE_HASH_TABLE_SIZE; i++) OutEdgeHashTable[i] =
- (EdgeStruct *) NULL;
- if (!InverseMatrix(GlblViewMat)) {
- fprintf(stderr,
- "\nNo inverse for matrix transformation, output is in screen space\n");
- GenUnitMat(GlblViewMat); /* No inverse transform at all. */
- }
- printf("Automatic Hidden Line generator\t\tGershon Elber\t\tJan. 1989\n");
-
- EdgeCount = 0;
-
- for (i=0; i<EDGE_HASH_TABLE_SIZE; i++)
- if ((PEtemp = EdgeHashTable[i]) != NULL)/* If any edge in that list. */
- while (PEtemp) {
- EdgeCount++;
- fprintf(stderr, "\b\b\b\b\b%5d", EdgeCount);
- PEtail = PEtemp -> Pnext; /* OutputEdge destroy it. */
- if ((!PEtemp -> Internal || InternalFlag) &&
- VisibleEdge(i, PEtemp, PolyHashTable))
- OutputEdge(PEtemp);
- PEtemp = PEtail;
- }
-
- PolyLineCount = EmitOutEdgeHashTable(); /* Output all polylines. */
- printf("[OBJECT Hidden"); /* Output the OBJECT keyword: */
- for (i=0; i<PolyLineCount; i++) {
- if (i % 10 == 0) printf("\n\t");
- printf("P%-3d ", i);
- }
- printf("]\n");
- fprintf(stderr, ", %d seconds.", time(NULL) - SaveTime);
- }
-
- /*****************************************************************************
- * Routine to output one edge to the OutEdgeHashTable. *
- * The edge is inserted into OutEdgeHashTable to be able to match it into *
- * the longest path possible - connecting edges into edge sequence. *
- * Each edge is inserted by its Ymin, which will cause the paths be in *
- * increased Y order... *
- *****************************************************************************/
- static void OutputEdge(EdgeStruct *PEtemp)
- {
- int Level;
-
- Level = (int) ((PEtemp -> Vertex[0] -> Coord[1] + 1.0) *
- EDGE_HASH_TABLE_SIZE2);
- PEtemp -> Pnext = OutEdgeHashTable[Level];
- OutEdgeHashTable[Level] = PEtemp;
- }
-
- /*****************************************************************************
- * Routine to scan the OutEdgeHashTable, and Emit the longest paths found in *
- * it by searching for consecutive edges and combining colinear edges. *
- *****************************************************************************/
- static int EmitOutEdgeHashTable(void)
- {
- int i, j, Colinear, VertexCount = 0, VertexBaseCount, PolylineCount = 0;
- double Vec[3];
- struct EdgeStruct *PEtemp, *PEnext;
-
- for (i=0; i<EDGE_HASH_TABLE_SIZE; i++) /* Scan all the hash table. */
- while (OutEdgeHashTable[i]) { /* Scan all edges in entry. */
- PEtemp = OutEdgeHashTable[i]; /* Take edge out of table. */
- OutEdgeHashTable[i] = OutEdgeHashTable[i] -> Pnext;
- VertexBaseCount = VertexCount;
-
- /* Print first vertex of polyline: */
- MultVecby4by4(Vec, PEtemp -> Vertex[0] -> Coord, GlblViewMat);
- printf("[VERTEX V%-4d %11lf %11lf %11lf]\n", VertexCount++,
- Vec[0], Vec[1], Vec[2]);
-
- while ((PEnext = FoundMatchEdge(&Colinear, PEtemp)) != NULL) {
- if (!Colinear) { /* Print PEtemp only if not colinear! */
- /* Print next vertices of polyline: */
- for (j=0; j<3; j++) Vec[j] =
- PEtemp -> Vertex[1] -> Coord[j];
- MultVecby4by4(Vec, PEtemp -> Vertex[1] -> Coord,
- GlblViewMat);
- printf("[VERTEX V%-4d %11lf %11lf %11lf]\n", VertexCount++,
- Vec[0], Vec[1], Vec[2]);
- }
- PEtemp = PEnext;
- }
-
- /* Print last vertex of polyline: */
- MultVecby4by4(Vec, PEtemp -> Vertex[1] -> Coord, GlblViewMat);
- printf("[VERTEX V%-4d %11lf %11lf %11lf]\n", VertexCount++,
- Vec[0], Vec[1], Vec[2]);
-
- printf("[POLYLINE P%-4d", PolylineCount++);
- for (j=VertexBaseCount; j<VertexCount; j++) {
- if ((j-VertexBaseCount) % 10 == 0) printf("\n\t");
- printf("V%-4d ", j);
- }
- printf("]\n");
- }
- return PolylineCount;
- }
-
- /*****************************************************************************
- * Routine to scan the OutEdgeHashTable for a match edge if any, delete it *
- * from HashTable and return it. if colinear with PEdge set Colinear to TRUE. *
- * return FALSE if no match found (end of polyline). *
- *****************************************************************************/
- static struct EdgeStruct *FoundMatchEdge(int *Colinear, EdgeStruct *PEdge)
- {
- int Level;
- struct EdgeStruct *PEtemp, *PElast;
-
- Level = (int) ((PEdge -> Vertex[1] -> Coord[1] + 1.0) *
- EDGE_HASH_TABLE_SIZE2);
- PEtemp = PElast = OutEdgeHashTable[Level];
- while (PEtemp) { /* First scan for colinear edge. */
- if (FuzzSamePoints(PEdge -> Vertex[1] -> Coord,
- PEtemp -> Vertex[0] -> Coord) &&
- ColinearPoints(PEdge -> Vertex[0] -> Coord,
- PEdge -> Vertex[1] -> Coord,
- PEtemp -> Vertex[1] -> Coord)) {
- *Colinear = TRUE;
- /* Delete that edge from hash table structure: */
- if (PEtemp == PElast)
- OutEdgeHashTable[Level] = OutEdgeHashTable[Level] -> Pnext;
- else PElast -> Pnext = PEtemp -> Pnext;
-
- if (FuzzSamePoints(PEtemp -> Vertex[0] -> Coord,
- PEtemp -> Vertex[1] -> Coord))
- return FoundMatchEdge(Colinear, PEdge);/* Call recursively! */
- else return PEtemp;
- }
- PElast = PEtemp;
- PEtemp = PEtemp -> Pnext;
- }
-
- PEtemp = PElast = OutEdgeHashTable[Level];
- while (PEtemp) { /* Next scan for any match edge. */
- if (FuzzSamePoints(PEdge -> Vertex[1] -> Coord,
- PEtemp -> Vertex[0] -> Coord)) {
- *Colinear = FALSE;
- /* Delete that edge from hash table structure: */
- if (PEtemp == PElast)
- OutEdgeHashTable[Level] = OutEdgeHashTable[Level] -> Pnext;
- else PElast -> Pnext = PEtemp -> Pnext;
-
- if (FuzzSamePoints(PEtemp -> Vertex[0] -> Coord,
- PEtemp -> Vertex[1] -> Coord))
- return FoundMatchEdge(Colinear, PEdge);/* Call recursively! */
- else return PEtemp;
- }
- PElast = PEtemp;
- PEtemp = PEtemp -> Pnext;
- }
-
- return (EdgeStruct *) NULL; /* No match - end of polyline. */
- }
-
- /*****************************************************************************
- * Routine to test if two points are almost the same, and returns TRUE if so. *
- *****************************************************************************/
- static int FuzzSamePoints(float Pt1[3], float Pt2[3])
- {
- return (APX_EQ(Pt1[0], Pt2[0]) &&
- APX_EQ(Pt1[1], Pt2[1]) &&
- APX_EQ(Pt1[2], Pt2[2]));
- }
-
- /*****************************************************************************
- * Routine to test if three points are colinear, and returns TRUE if so... *
- * Algorithm: cross product should be zero if colinear... *
- * Note this routine does not return TRUE if Pt2 is not between Pt1..Pt3. *
- *****************************************************************************/
- static int ColinearPoints(float Pt1[3], float Pt2[3], float Pt3[3])
- {
- int i;
- float Xout, Yout, Zout, U[3], V[3], temp;
-
- for (i=0; i<3; i++) {
- U[i] = Pt2[i] - Pt1[i];
- V[i] = Pt3[i] - Pt2[i];
- }
- temp = sqrt(SQR(U[0]) + SQR(U[1]) + SQR(U[2]));
- if (APX_EQ(temp, 0.0)) return TRUE;
- for (i=0; i<3; i++) U[i] = U[i] / temp;
-
- temp = sqrt(SQR(V[0]) + SQR(V[1]) + SQR(V[2]));
- if (APX_EQ(temp, 0.0)) return TRUE;
- for (i=0; i<3; i++) V[i] = V[i] / temp;
-
- /* Xoutput = Uy * Vz - Uz * Vy. */
- Xout = U[1] /* Uy */ * V[2] /* Vz */ -
- U[2] /* Uz */ * V[1] /* Vy */;
-
- /* Youtput = Uz * Vx - Ux * Vz. */
- Yout = U[2] /* Uz */ * V[0] /* Vx */ -
- U[0] /* Ux */ * V[2] /* Vz */;
-
- /* Zoutput = Ux * Vy - Uy * Vx. */
- Zout = U[0] /* Ux */ * V[1] /* Vy */ -
- U[1] /* Uy */ * V[0] /* Vx */;
-
- if (APX_EQ(Xout, 0.0) && APX_EQ(Yout, 0.0) && APX_EQ(Zout, 0.0) &&
- ((MIN(Pt1[0], Pt3[0]) < Pt2[0]) && (MAX(Pt1[0], Pt3[0]) > Pt2[0]) &&
- (MIN(Pt1[1], Pt3[1]) < Pt2[1]) && (MAX(Pt1[1], Pt3[1]) > Pt2[1])))
- return TRUE;
- else return FALSE;
- }
-
- /*****************************************************************************
- * Routine to test the visibility of the given edge relative to all polygons *
- * in polygon list. return TRUE if the edge is visible. It is assumed that *
- * the edge is whole visible or whole invisible (Pass 3 broke the edge if *
- * that whas not true). Also it is assumed the polygons are all convex. *
- * A short cut is made to test the edge only against the needed polygons *
- * only, using the polygon hash table and Y level sorting. *
- *****************************************************************************/
- static int VisibleEdge(int EdgeMinY, EdgeStruct * PEdge,
- PolygonStruct *PolyHashTable[])
- {
- int EdgeMaxY, i;
- PolygonStruct *PPolyList, *PPolyLast;
-
- EdgeMaxY = MIN((MAX(PEdge -> Vertex[0] -> Coord[1],
- PEdge -> Vertex[1] -> Coord[1]) + 1.0) *
- EDGE_HASH_TABLE_SIZE2,
- EDGE_HASH_TABLE_SIZE1);
-
- /* Test the edge only in the interval 0..EdgeMaxY as these are the only */
- /* which might hide that edge. Also polygons with MaxY less than */
- /* EdgeMinY are deleted from PolyHashTable as it is assumed the edges */
- /* are scanned in increasing order of the EdgeHashTable. */
- for (i=0; i<=EdgeMaxY; i++) {
- PPolyList = PPolyLast = PolyHashTable[i];
- while (PPolyList) {
- if ((PPolyList -> Ymax + 1.0) * EDGE_HASH_TABLE_SIZE2 < EdgeMinY)
- /* Delete this polygon! */
- if (PPolyList == PPolyLast) {
- PolyHashTable[i] = PPolyLast = PPolyList -> Pnext;
- PPolyList = PPolyList -> Pnext;
- }
- else {
- PPolyList = PPolyList -> Pnext;
- PPolyLast -> Pnext = PPolyList;
- }
- else { /* Polygon still active - test edge against it. */
- /* If found one polygon that hides this edge return FALSE... */
-
- if (!VisibleEdgeOnePoly(PEdge, PPolyList)) return FALSE;
- PPolyLast = PPolyList;
- PPolyList = PPolyList -> Pnext;
- }
- }
- }
-
- return TRUE;
- }
-
- /*****************************************************************************
- * Routine to test the visibility of the given edge relative to one polygon *
- * return TRUE if the edge is visible. It is assumed that the edge is whole *
- * visible or whole invisible (Pass 3 broke the edge if that whas not true). *
- * Also it is assumed the polygons are all convex. *
- *****************************************************************************/
- static int VisibleEdgeOnePoly(EdgeStruct *PEdge, PolygonStruct *PPoly)
- {
- int i;
- float MidPt[3], Temp;
- struct VertexStruct *PList;
-
- for (i=0; i<3; i++) MidPt[i] = /* Calc a mid point on the edge: */
- (PEdge -> Vertex[0] -> Coord[i] +
- PEdge -> Vertex[1] -> Coord[i]) / 2.0;
-
- /* Test if edges is out of polygon boundary box: */
- if (MidPt[0] > PPoly -> Xmax || MidPt[0] < PPoly -> Xmin ||
- MidPt[1] > PPoly -> Ymax || MidPt[1] < PPoly -> Ymin) return TRUE;
-
- Temp = PPoly -> Plane[0] * MidPt[0] +
- PPoly -> Plane[1] * MidPt[1] +
- PPoly -> Plane[2] * MidPt[2] +
- PPoly -> Plane[3];
- if ((Temp >= 0) || (APX_EQ(Temp, 0.0)))
- return TRUE; /* Edge in front of polygon. */
-
- /* We cannt escape it - we now must find if the point is included in */
- /* polygon area. We assume the polygon is convex and use the fact */
- /* that the polygon list is ordered such that the cross product */
- /* of two consecutive vertices and the point is positive for all */
- /* consecutive vertices pairs iff the point is in the polygon. */
- PList = PPoly -> PVertex;
- while (PList -> Pnext) {
- if (CrossProd(PList -> Coord, PList -> Pnext -> Coord, MidPt) < 0)
- return TRUE; /* Out of polygon! */
- PList = PList -> Pnext;
- }
- /* Now test last polygon edge (last point, first point in poly list) */
- if (CrossProd(PList -> Coord, PPoly -> PVertex -> Coord, MidPt) < 0)
- return TRUE; /* Out of polygon! */
-
- return FALSE;
- }
-
- /*****************************************************************************
- * Procedure to calculate the INVERSE of a given MatrixType matrix A which is *
- * modified to the inverted matrix. Return TRUE if inverse exists. *
- *****************************************************************************/
- static int InverseMatrix(MatrixType A)
- {
- MatrixType InvA;
- int i, j, k;
- double V;
-
- GenUnitMat(InvA);
-
- for (i=0; i<4; i++) {
- V = A[i][i]; /* Find the new pivot. */
- k = i;
- for (j=i+1; j<4; j++) if (A[j][i] > V) {
- /* Find maximum on col i, row i+1..4. */
- V = A[j][i];
- k = j;
- }
- j = k;
-
- if (i != j) for (k=0; k<4; k++) {
- SwapDouble(&A[i][k], &A[j][k]);
- SwapDouble(&InvA[i][k], &InvA[j][k]);
- }
-
- for (j=i+1; j<4; j++) { /* Eliminate col i from row i+1..4. */
- V = A[j][i] / A[i][i];
- for (k=0; k<4; k++) {
- A[j][k] -= V * A[i][k];
- InvA[j][k] -= V * InvA[i][k];
- }
- }
- }
-
- for (i=4-1; 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]; */
- InvA[j][k] -= V * InvA[i][k];
- }
- }
- }
-
- for (i=0; i<4; i++) /* Normalize the inverse Matrix. */
- for (j=0; j<4; j++)
- InvA[i][j] /= A[i][i];
- for (i=0; i<4; i++) /* Copy inverted matrix to A. */
- for (j=0; j<4; j++)
- A[i][j] = InvA[i][j];
-
- return TRUE;
- }
-
- /*****************************************************************************
- * Procedure to swap two double parameters: *
- *****************************************************************************/
- static void SwapDouble(double *D1, double *D2)
- {
- double D;
-
- D = (*D1);
- *D1 = (*D2);
- *D2 = D;
- }
-
-