g4tools  5.4.0
normal
Go to the documentation of this file.
1 // see license file for original license.
2 
3 #ifndef tools_glutess_normal
4 #define tools_glutess_normal
5 
6 #include "_tess"
7 
8 /* __gl_projectPolygon( tess ) determines the polygon normal
9  * and project vertices onto the plane of the polygon.
10  */
11 //void __gl_projectPolygon( GLUtesselator *tess );
12 
16 #include <cmath>
17 
18 #define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
19 
20 inline/*static*/ int static_LongAxis( GLUdouble v[3] )
21 {
22  int i = 0;
23 
24  if( GLU_ABS(v[1]) > GLU_ABS(v[0]) ) { i = 1; }
25  if( GLU_ABS(v[2]) > GLU_ABS(v[i]) ) { i = 2; }
26  return i;
27 }
28 
29 inline/*static*/ void static_ComputeNormal( GLUtesselator *tess, GLUdouble norm[3] )
30 {
31  GLUvertex *v, *v1, *v2;
32  GLUdouble c, tLen2, maxLen2;
33  GLUdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
34  GLUvertex *maxVert[3], *minVert[3];
35  GLUvertex *vHead = &tess->mesh->vHead;
36  int i;
37 
38  maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
39  minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
40 
41  minVert[0] = 0;minVert[1] = 0;minVert[2] = 0; //G.Barrand : to quiet Coverity.
42  maxVert[0] = 0;maxVert[1] = 0;maxVert[2] = 0; //G.Barrand : to quiet Coverity.
43 
44  for( v = vHead->next; v != vHead; v = v->next ) {
45  for( i = 0; i < 3; ++i ) {
46  c = v->coords[i];
47  if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
48  if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
49  }
50  }
51 
52  /* Find two vertices separated by at least 1/sqrt(3) of the maximum
53  * distance between any two vertices
54  */
55  i = 0;
56  if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
57  if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
58  if( minVal[i] >= maxVal[i] ) {
59  /* All vertices are the same -- normal doesn't matter */
60  norm[0] = 0; norm[1] = 0; norm[2] = 1;
61  return;
62  }
63 
64  /* Look for a third vertex which forms the triangle with maximum area
65  * (Length of normal == twice the triangle area)
66  */
67  maxLen2 = 0;
68  v1 = minVert[i];
69  v2 = maxVert[i];
70  if( !v1 || !v2 ) {norm[0] = 0; norm[1] = 0; norm[2] = 1;return;} //G.Barrand.
71  d1[0] = v1->coords[0] - v2->coords[0];
72  d1[1] = v1->coords[1] - v2->coords[1];
73  d1[2] = v1->coords[2] - v2->coords[2];
74  for( v = vHead->next; v != vHead; v = v->next ) {
75  d2[0] = v->coords[0] - v2->coords[0];
76  d2[1] = v->coords[1] - v2->coords[1];
77  d2[2] = v->coords[2] - v2->coords[2];
78  tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
79  tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
80  tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
81  tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
82  if( tLen2 > maxLen2 ) {
83  maxLen2 = tLen2;
84  norm[0] = tNorm[0];
85  norm[1] = tNorm[1];
86  norm[2] = tNorm[2];
87  }
88  }
89 
90  if( maxLen2 <= 0 ) {
91  /* All points lie on a single line -- any decent normal will do */
92  norm[0] = norm[1] = norm[2] = 0;
93  norm[static_LongAxis(d1)] = 1;
94  }
95 }
96 
97 
98 inline/*static*/ void static_CheckOrientation( GLUtesselator *tess )
99 {
100  GLUdouble area;
101  GLUface *f, *fHead = &tess->mesh->fHead;
102  GLUvertex *v, *vHead = &tess->mesh->vHead;
103  GLUhalfEdge *e;
104 
105  /* When we compute the normal automatically, we choose the orientation
106  * so that the sum of the signed areas of all contours is non-negative.
107  */
108  area = 0;
109  for( f = fHead->next; f != fHead; f = f->next ) {
110  e = f->anEdge;
111  if( e->winding <= 0 ) continue;
112  do {
113  area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
114  e = e->Lnext;
115  } while( e != f->anEdge );
116  }
117  if( area < 0 ) {
118  /* Reverse the orientation by flipping all the t-coordinates */
119  for( v = vHead->next; v != vHead; v = v->next ) {
120  v->t = - v->t;
121  }
122  tess->tUnit[0] = - tess->tUnit[0];
123  tess->tUnit[1] = - tess->tUnit[1];
124  tess->tUnit[2] = - tess->tUnit[2];
125  }
126 }
127 
128 #if defined(SLANTED_SWEEP)
129 /* The "feature merging" is not intended to be complete. There are
130  * special cases where edges are nearly parallel to the sweep line
131  * which are not implemented. The algorithm should still behave
132  * robustly (ie. produce a reasonable tesselation) in the presence
133  * of such edges, however it may miss features which could have been
134  * merged. We could minimize this effect by choosing the sweep line
135  * direction to be something unusual (ie. not parallel to one of the
136  * coordinate axes).
137  */
138 #define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
139 #define S_UNIT_Y 0.86052074622010633
140 #else
141 #define S_UNIT_X 1.0
142 #define S_UNIT_Y 0.0
143 #endif
144 
145 /* Determine the polygon normal and project vertices onto the plane
146  * of the polygon.
147  */
148 inline void __gl_projectPolygon( GLUtesselator *tess )
149 {
150  GLUvertex *v, *vHead = &tess->mesh->vHead;
151  GLUdouble norm[3];
152  GLUdouble *sUnit, *tUnit;
153  int i, computedNormal = TOOLS_GLU_FALSE;
154 
155  norm[0] = tess->normal[0];
156  norm[1] = tess->normal[1];
157  norm[2] = tess->normal[2];
158  if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
159  static_ComputeNormal( tess, norm );
160  computedNormal = TOOLS_GLU_TRUE;
161  }
162  sUnit = tess->sUnit;
163  tUnit = tess->tUnit;
164  i = static_LongAxis( norm );
165 
166 #if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
167  /* Choose the initial sUnit vector to be approximately perpendicular
168  * to the normal.
169  */
170  Normalize( norm );
171 
172  sUnit[i] = 0;
173  sUnit[(i+1)%3] = S_UNIT_X;
174  sUnit[(i+2)%3] = S_UNIT_Y;
175 
176  /* Now make it exactly perpendicular */
177  w = Dot( sUnit, norm );
178  sUnit[0] -= w * norm[0];
179  sUnit[1] -= w * norm[1];
180  sUnit[2] -= w * norm[2];
181  Normalize( sUnit );
182 
183  /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
184  tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
185  tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
186  tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
187  Normalize( tUnit );
188 #else
189  /* Project perpendicular to a coordinate axis -- better numerically */
190  sUnit[i] = 0;
191  sUnit[(i+1)%3] = S_UNIT_X;
192  sUnit[(i+2)%3] = S_UNIT_Y;
193 
194  tUnit[i] = 0;
195  tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
196  tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
197 #endif
198 
199  /* Project the vertices onto the sweep plane */
200  for( v = vHead->next; v != vHead; v = v->next ) {
201  v->s = Dot( v->coords, sUnit );
202  v->t = Dot( v->coords, tUnit );
203  }
204  if( computedNormal ) {
205  static_CheckOrientation( tess );
206  }
207 }
208 
209 #endif
GLUmesh::fHead
GLUface fHead
Definition: mesh:133
S_UNIT_Y
#define S_UNIT_Y
Definition: normal:142
tools::area
void area(const VEC3 &a_p0, const VEC3 &a_p1, const VEC3 &a_p2, typename VEC3::elem_t &a_value, VEC3 &a_tmp_1, VEC3 &a_tmp_2, VEC3 &a_tmp_3)
Definition: vec3:354
GLUtesselator::tUnit
GLUdouble tUnit[3]
Definition: _tess:43
GLUvertex::s
GLUdouble s
Definition: mesh:90
GLUvertex::next
GLUvertex * next
Definition: mesh:83
S_UNIT_X
#define S_UNIT_X
Definition: normal:141
GLUmesh::vHead
GLUvertex vHead
Definition: mesh:132
static_CheckOrientation
inline void static_CheckOrientation(GLUtesselator *tess)
Definition: normal:98
GLUtesselator::normal
GLUdouble normal[3]
Definition: _tess:41
GLUhalfEdge::Lnext
GLUhalfEdge * Lnext
Definition: mesh:110
GLU_ABS
#define GLU_ABS(x)
Definition: _glu:74
__gl_projectPolygon
void __gl_projectPolygon(GLUtesselator *tess)
Definition: normal:148
GLUhalfEdge
Definition: mesh:106
GLUhalfEdge::winding
int winding
Definition: mesh:116
TOOLS_GLU_TRUE
#define TOOLS_GLU_TRUE
Definition: _glu:82
GLUdouble
double GLUdouble
Definition: _glu:16
GLUtesselator::mesh
GLUmesh * mesh
Definition: _tess:34
TOOLS_GLU_FALSE
#define TOOLS_GLU_FALSE
Definition: _glu:81
GLUtesselator
Definition: _tess:27
static_LongAxis
inline int static_LongAxis(GLUdouble v[3])
Definition: normal:20
GLUvertex
Definition: mesh:82
GLUtesselator::sUnit
GLUdouble sUnit[3]
Definition: _tess:42
GLUvertex::coords
GLUdouble coords[3]
Definition: mesh:89
GLUvertex::t
GLUdouble t
Definition: mesh:90
GLUface
Definition: mesh:94
GLUhalfEdge::Org
GLUvertex * Org
Definition: mesh:111
GLUface::next
GLUface * next
Definition: mesh:95
Dot
#define Dot(u, v)
inlined C code : ///////////////////////////////////
Definition: normal:18
static_ComputeNormal
inline void static_ComputeNormal(GLUtesselator *tess, GLUdouble norm[3])
Definition: normal:29
_tess
GLUface::anEdge
GLUhalfEdge * anEdge
Definition: mesh:97
GLU_TESS_MAX_COORD
#define GLU_TESS_MAX_COORD
Definition: _glu:90