Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

Face.cpp

Go to the documentation of this file.
00001 
00002 /*
00003     TEDDY - General graphics application library
00004     Copyright (C) 1999-2002  Timo Suoranta
00005     tksuoran@cc.helsinki.fi
00006 
00007     This library is free software; you can redistribute it and/or
00008     modify it under the terms of the GNU Lesser General Public
00009     License as published by the Free Software Foundation; either
00010     version 2.1 of the License, or (at your option) any later version.
00011 
00012     This library is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015     Lesser General Public License for more details.
00016 
00017     You should have received a copy of the GNU Lesser General Public
00018     License along with this library; if not, write to the Free Software
00019     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 
00021     $Id: Face.cpp,v 1.5 2002/02/16 12:41:39 tksuoran Exp $
00022 */
00023 
00024 
00025 #include "Teddy/Models/Face.h"
00026 #include "Teddy/Models/Vertex.h"
00027 #include "Teddy/PhysicalComponents/Projection.h"
00028 #include "Teddy/SysSupport/Messages.h"
00029 #include "Teddy/SysSupport/StdIO.h"
00030 #ifndef SWIG
00031 #include <algorithm>
00032 using namespace std;
00033 #endif
00034 
00035 
00036 namespace Teddy  {
00037 namespace Models {
00038 
00039 
00040 #define FACE_NORMAL_EPSILON (double)(0.0002)
00041 
00042 
00044 Face::Face()
00045 :
00046 Element(0)
00047 {
00048 }
00049 
00051 /*virtual*/ Face::~Face(){
00052 }
00053 
00054 
00056 /*virtual*/ void Face::add( Vertex *v ){
00057     vertices.push_front( v );
00058     v->addFace( this );
00059 }
00060 
00061 
00063 /*virtual*/ void Face::add( const float x, const float y, const float z ){
00064     Vertex *v = new Vertex(x,y,z);
00065     vertices.push_front( v );
00066     v->addFace( this );
00067 }
00068 
00069 
00071 /*virtual*/ void Face::append( Vertex *v ){
00072     vertices.push_back( v );
00073     v->addFace( this );
00074 }
00075 
00076 
00078 /*virtual*/ void Face::append( const float x, const float y, const float z ){
00079     Vertex *v = new Vertex(x,y,z);
00080     vertices.push_back( v );
00081     v->addFace( this );
00082 }
00083 
00084 
00086 /*virtual*/ void Face::draw( Projection *p ){
00087     p->beginPolygon();
00088 
00089     if( isEnabled(EL_USE_ELEMENT_NORMAL|EL_HAS_ELEMENT_NORMAL) ){
00090         dmsg( M_MAT, "Drawing flat face" );
00091         p->normal( normal );
00092     }else{
00093         dmsg( M_MAT, "Drawing smoothed face" );
00094     }
00095 
00096     list<Vertex*>::const_iterator v_it = vertices.begin();
00097     while( v_it != vertices.end() ){
00098         (*v_it)->draw( p );
00099         v_it++;
00100     }
00101 
00102     p->end();
00103 }
00104 
00105 
00136 /*virtual*/ void Face::smooth( float max_smoothing_angle ){
00137     //  Face which has no normal calculated can not be smoothed
00138     //  Face normal is needed even if face is not smoothed
00139     if( isDisabled(EL_HAS_ELEMENT_NORMAL) ){
00140         makeNormal();
00141     }
00142 
00143     //  If the max smoothing angle is set to less or equal to zero,
00144     //  smoothing can not be applied.
00145     if( max_smoothing_angle <= 0 ){
00146         enable ( EL_USE_ELEMENT_NORMAL );
00147         disable( EL_USE_VERTEX_NORMALS );
00148         return;
00149     }
00150 
00151     int  flat_count   = 0;
00152     int  share_count  = 0;
00153     int  smooth_count = 0;
00154     bool flat         = true;
00155 
00156     //  For each vertex in the Face
00157     list<Vertex*>::iterator  v_it = vertices.begin();
00158     while( v_it != vertices.end() ){
00159         Vertex *old_vertex = *v_it;
00160 
00161         //  Make a new Vertex. We will add each normal of
00162         //  Faces that participate in the smoothing and
00163         //  normalize the normal in the end.
00164         Vertex *new_vertex = new Vertex( old_vertex );
00165 
00166         //  Set the normal of each vertex to the normal of this face in the start
00167         new_vertex->setNormal( this->getNormal() );
00168 
00169         //  For each other Face that use this Vertex,
00170         //  test the normal difference. On the way we
00171         //  also calculate the new normal the the new
00172         //  Vertex
00173         share_count  = 1;
00174         smooth_count = 0;
00175         flat_count   = 0;
00176         list<Face*>::iterator f_it = old_vertex->getFaces().begin();
00177         while( f_it != old_vertex->getFaces().end() ){
00178             Face *other = *f_it;
00179 
00180             //  Skip if same Face
00181             if( other == this ){
00182                 f_it++;             
00183                 continue;
00184             }
00185 
00186             //  Bad Face?
00187             if( other == NULL ){
00188                 emsg( M_MAT, "NULL face in vertex cross-reference" );
00189                 f_it++;
00190                 continue;
00191             }
00192 
00193             //  The other face must have a normal as well
00194             if( other->isDisabled(EL_HAS_ELEMENT_NORMAL) ){
00195                 other->makeNormal();
00196             }
00197 
00198             //  Calculate Face normal difference.
00199             //  We have earlier ensured that both Faces do have a normal.
00200             share_count++;
00201             Vector n1      = this ->getNormal();
00202             Vector n2      = other->getNormal();
00203             float  fn_ang  = (float)(  fabs( n1.angle(n2) )  );
00204             float  fn_diff = max_smoothing_angle - fn_ang;
00205 
00206             //  Is the enough different and not too much different?
00207             if( fn_ang > FACE_NORMAL_EPSILON && fn_diff > FLT_MIN ){
00208                 new_vertex->addNormal( n2 );
00209                 smooth_count++;
00210                 //  If the face was considered flat earlier,
00211                 //  we need to set normal to the vertices processed
00212                 //  so far
00213                 if( flat == true ){
00214                     flat = false;
00215 
00216                     Vector                  normal   = this->getNormal();
00217                     list<Vertex*>::iterator v_it_fix = vertices.begin();
00218                     if( v_it_fix != v_it ){
00219                         Vertex *v = *v_it_fix;
00220                         v->setNormal( normal );
00221                         v_it_fix++;
00222                     }
00223                 }
00224             }else{  //  Otherwise it is too close or too different
00225                 flat_count++;
00226             }
00227             f_it++;
00228         }
00229 
00230         //  Finalize the new Vertex normal; normalize it
00231         new_vertex->normNormal();
00232 
00233         //  If the Face is not flat, we will need to store the new Vertex normal
00234 //      if( flat == false ){
00235             dmsg( M_VERT,
00236                 "Face %ld smoothed vertices %ld flat vertices %ld faces share",
00237                 smooth_count,
00238                 flat_count,
00239                 share_count
00240             );
00241             //  If the old Vertex has no normal, we can store the normal information there
00242             if( old_vertex->isDisabled(VX_HAS_NORMAL) ){
00243                 old_vertex->setNormal( new_vertex->getNormal() );
00244                 dmsg( M_VERT,
00245                     "Old vertex %ld had no normal, setting it to (%.5f, %.5f, %.5f)",
00246                     (unsigned long)(old_vertex),
00247                     new_vertex->getNormal().v[0],
00248                     new_vertex->getNormal().v[1],
00249                     new_vertex->getNormal().v[2]
00250                     );
00251                 delete new_vertex;
00252             }else{
00253                 //  If the old Vertex normal different, replace the
00254                 //  Vertex in this Faces vertex list with the new Vertex
00255                 //  This will not change the old Vertex, and other Faces'
00256                 //  Vertex lists will not be changed.
00257                 Vector old_normal = old_vertex->getNormal();
00258                 Vector new_normal = new_vertex->getNormal();
00259                 float vn_ang  = (float)(  fabs( old_normal.angle(new_normal) )  );
00260                 if( vn_ang > FACE_NORMAL_EPSILON /*&& vn_diff > FLT_MIN*/ ){
00261                     dmsg( M_VERT,
00262                         "Old vertex %ld had different %.5f normal, replacing with copy (%.5f, %.5f, %.5f)",
00263                         old_vertex,
00264                         vn_ang,
00265                         new_vertex->getNormal().v[0],
00266                         new_vertex->getNormal().v[1],
00267                         new_vertex->getNormal().v[2]
00268                     );
00269                     //new_vertex->debug();
00270                     *v_it = new_vertex;
00271                 }else{
00272                     dmsg( M_VERT,
00273                         "Old vertex %ld had the same normal %.5f",
00274                         vn_ang,
00275                         old_vertex
00276                     );
00277                     delete new_vertex;
00278 
00279                 }
00280                 //  Otherwise, the old vertex has the same normal as the new
00281                 //  vertex and we do nothing
00282             }
00283         /*}else{
00284             delete new_vertex;
00285         } */
00286         
00287         v_it++;
00288     }
00289 
00290 
00291     if( flat == false ){
00292         disable( EL_USE_ELEMENT_NORMAL );
00293         enable ( EL_USE_VERTEX_NORMALS );
00294 
00295         list<Vertex*>::iterator  v_it_check = vertices.begin();
00296         while( v_it_check != vertices.end() ){
00297             Vertex *check_vertex = *v_it_check;
00298             if( check_vertex->isDisabled(VX_HAS_NORMAL) ){
00299                 check_vertex->debug();
00300                 dmsg( M_VERT, "This smooth Face has Vertex with no normal!" );
00301             }
00302             v_it_check++;
00303         }
00304     }else{
00305         list<Vertex*>::iterator v_it_check = vertices.begin();
00306         while( v_it_check != vertices.end() ){
00307             Vertex *check_vertex = *v_it_check;
00308             check_vertex->setNormal( this->getNormal() );
00309 /*          if( check_vertex->isDisabled(VX_HAS_NORMAL) ){
00310                 check_vertex->debug();
00311                 vert_debug_msg( "This smooth Face has Vertex with no normal!" );
00312             }*/
00313             v_it_check++;
00314         }
00315 
00316 //?     v->disable( VX_USE_THIS_NORMAL | VX_USE_PARENT_NORMAL );
00317         enable( EL_HAS_ELEMENT_NORMAL | EL_USE_ELEMENT_NORMAL );
00318         //debug_msg( "This face is now FLAT" );
00319         //debug_msg( "This face is now SMOOTH" );
00320     }
00321 }
00322 
00323 
00324 #if 0
00325 /*virtual*/ bool Face::stepCSGFace( GeometryIterator *gi ){
00326     return false;
00327 }
00328 
00329 
00330 /*virtual*/ void Face::fillCSGFace( GeometryIterator *gi, CSG_IFace *face ){
00331 //  face->user_face_data        = 0;
00332 //  face->user_face_vertex_data = 0;
00333     //face->vertex_index =
00334 }
00335 #endif
00336 
00337 
00338 };  //  namespace Models
00339 };  //  namespace Teddy
00340 
00341 
00342 
00343 #if 0
00344 
00345 
00346 // ** THIS IS A CODE SNIPPET WHICH WILL EFFICIEINTLY TRIANGULATE ANY
00347 // ** POLYGON/CONTOUR (without holes) AS A STATIC CLASS.  THIS SNIPPET
00348 // ** IS COMPRISED OF 3 FILES, TRIANGULATE.H, THE HEADER FILE FOR THE
00349 // ** TRIANGULATE BASE CLASS, TRIANGULATE.CPP, THE IMPLEMENTATION OF
00350 // ** THE TRIANGULATE BASE CLASS, AND TEST.CPP, A SMALL TEST PROGRAM
00351 // ** DEMONSTRATING THE USAGE OF THE TRIANGULATOR.  THE TRIANGULATE
00352 // ** BASE CLASS ALSO PROVIDES TWO USEFUL HELPER METHODS, ONE WHICH
00353 // ** COMPUTES THE AREA OF A POLYGON, AND ANOTHER WHICH DOES AN EFFICENT
00354 // ** POINT IN A TRIANGLE TEST.
00355 // ** SUBMITTED BY JOHN W. RATCLIFF (jratcliff@verant.com) July 22, 2000
00356 
00357 /**********************************************************************/
00358 /************ HEADER FILE FOR TRIANGULATE.H ***************************/
00359 /**********************************************************************/
00360 
00361 
00362 #ifndef TRIANGULATE_H
00363 
00364 #define TRIANGULATE_H
00365 
00366 /*****************************************************************/
00379 /*****************************************************************/
00380 
00381 
00382 #include <vector>  // Include STL vector class.
00383 
00384 class Vector2d
00385 {
00386 public:
00387   Vector2d(float x,float y)
00388   {
00389     Set(x,y);
00390   };
00391 
00392   float GetX(void) const { return mX; };
00393 
00394   float GetY(void) const { return mY; };
00395 
00396   void  Set(float x,float y)
00397   {
00398     mX = x;
00399     mY = y;
00400   };
00401 private:
00402   float mX;
00403   float mY;
00404 };
00405 
00406 // Typedef an STL vector of vertices which are used to represent
00407 // a polygon/contour and a series of triangles.
00408 typedef std::vector< Vector2d > Vector2dVector;
00409 
00410 
00411 class Triangulate
00412 {
00413 public:
00414 
00415   // triangulate a contour/polygon, places results in STL vector
00416   // as series of triangles.
00417   static bool Process(const Vector2dVector &contour,
00418                       Vector2dVector &result);
00419 
00420   // compute area of a contour/polygon
00421   static float Area(const Vector2dVector &contour);
00422 
00423   // decide if point Px/Py is inside triangle defined by
00424   // (Ax,Ay) (Bx,By) (Cx,Cy)
00425   static bool InsideTriangle(float Ax, float Ay,
00426                       float Bx, float By,
00427                       float Cx, float Cy,
00428                       float Px, float Py);
00429 
00430 
00431 private:
00432   static bool Snip(const Vector2dVector &contour,int u,int v,int w,int n,int *V);
00433 
00434 };
00435 
00436 
00437 #endif
00438 
00439 /**************************************************************************/
00440 /*** END OF HEADER FILE TRIANGULATE.H BEGINNING OF CODE TRIANGULATE.CPP ***/
00441 /**************************************************************************/
00442 
00443 
00444 #include <stdio.h>
00445 #include <stdlib.h>
00446 #include <string.h>
00447 #include <assert.h>
00448 
00449 #include "triangulate.h"
00450 
00451 static const float EPSILON=0.0000000001f;
00452 
00453 float Triangulate::Area(const Vector2dVector &contour)
00454 {
00455 
00456   int n = contour.size();
00457 
00458   float A=0.0f;
00459 
00460   for(int p=n-1,q=0; q<n; p=q++)
00461   {
00462     A+= contour[p].GetX()*contour[q].GetY() - contour[q].GetX()*contour[p].GetY();
00463   }
00464   return A*0.5f;
00465 }
00466 
00467    /*
00468      InsideTriangle decides if a point P is Inside of the triangle
00469      defined by A, B, C.
00470    */
00471 bool Triangulate::InsideTriangle(float Ax, float Ay,
00472                       float Bx, float By,
00473                       float Cx, float Cy,
00474                       float Px, float Py)
00475 
00476 {
00477   float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
00478   float cCROSSap, bCROSScp, aCROSSbp;
00479 
00480   ax = Cx - Bx;  ay = Cy - By;
00481   bx = Ax - Cx;  by = Ay - Cy;
00482   cx = Bx - Ax;  cy = By - Ay;
00483   apx= Px - Ax;  apy= Py - Ay;
00484   bpx= Px - Bx;  bpy= Py - By;
00485   cpx= Px - Cx;  cpy= Py - Cy;
00486 
00487   aCROSSbp = ax*bpy - ay*bpx;
00488   cCROSSap = cx*apy - cy*apx;
00489   bCROSScp = bx*cpy - by*cpx;
00490 
00491   return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
00492 };
00493 
00494 bool Triangulate::Snip(const Vector2dVector &contour,int u,int v,int w,int n,int *V)
00495 {
00496   int p;
00497   float Ax, Ay, Bx, By, Cx, Cy, Px, Py;
00498 
00499   Ax = contour[V[u]].GetX();
00500   Ay = contour[V[u]].GetY();
00501 
00502   Bx = contour[V[v]].GetX();
00503   By = contour[V[v]].GetY();
00504 
00505   Cx = contour[V[w]].GetX();
00506   Cy = contour[V[w]].GetY();
00507 
00508   if ( EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) ) return false;
00509 
00510   for (p=0;p<n;p++)
00511   {
00512     if( (p == u) || (p == v) || (p == w) ) continue;
00513     Px = contour[V[p]].GetX();
00514     Py = contour[V[p]].GetY();
00515     if (InsideTriangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py)) return false;
00516   }
00517 
00518   return true;
00519 }
00520 
00521 bool Triangulate::Process(const Vector2dVector &contour,Vector2dVector &result)
00522 {
00523   /* allocate and initialize list of Vertices in polygon */
00524 
00525   int n = contour.size();
00526   if ( n < 3 ) return false;
00527 
00528   int *V = new int[n];
00529 
00530   /* we want a counter-clockwise polygon in V */
00531 
00532   if ( 0.0f < Area(contour) )
00533     for (int v=0; v<n; v++) V[v] = v;
00534   else
00535     for(int v=0; v<n; v++) V[v] = (n-1)-v;
00536 
00537   int nv = n;
00538 
00539   /*  remove nv-2 Vertices, creating 1 triangle every time */
00540   int count = 2*nv;   /* error detection */
00541 
00542   for(int m=0, v=nv-1; nv>2; )
00543   {
00544     /* if we loop, it is probably a non-simple polygon */
00545     if (0 >= (count--))
00546     {
00547       //** Triangulate: ERROR - probable bad polygon!
00548       return false;
00549     }
00550 
00551     /* three consecutive vertices in current polygon, <u,v,w> */
00552     int u = v  ; if (nv <= u) u = 0;     /* previous */
00553     v = u+1; if (nv <= v) v = 0;     /* new v    */
00554     int w = v+1; if (nv <= w) w = 0;     /* next     */
00555 
00556     if ( Snip(contour,u,v,w,nv,V) )
00557     {
00558       int a,b,c,s,t;
00559 
00560       /* true names of the vertices */
00561       a = V[u]; b = V[v]; c = V[w];
00562 
00563       /* output Triangle */
00564       result.push_back( contour[a] );
00565       result.push_back( contour[b] );
00566       result.push_back( contour[c] );
00567 
00568       m++;
00569 
00570       /* remove v from remaining polygon */
00571       for(s=v,t=v+1;t<nv;s++,t++) V[s] = V[t]; nv--;
00572 
00573       /* resest error detection counter */
00574       count = 2*nv;
00575     }
00576   }
00577 
00578 
00579 
00580   delete V;
00581 
00582   return true;
00583 }
00584 
00585 
00586 /************************************************************************/
00587 /*** END OF CODE SECTION TRIANGULATE.CPP BEGINNING OF TEST.CPP A SMALL **/
00588 /*** TEST APPLICATION TO DEMONSTRATE THE USAGE OF THE TRIANGULATOR     **/
00589 /************************************************************************/
00590 
00591 #include <stdio.h>
00592 #include <stdlib.h>
00593 #include <string.h>
00594 #include <assert.h>
00595 
00596 
00597 #include "triangulate.h"
00598 
00599 void main(int argc,char **argv)
00600 {
00601 
00602   // Small test application demonstrating the usage of the triangulate
00603   // class.
00604 
00605 
00606   // Create a pretty complicated little contour by pushing them onto
00607   // an stl vector.
00608 
00609   Vector2dVector a;
00610 
00611   a.push_back( Vector2d(0,6));
00612   a.push_back( Vector2d(0,0));
00613   a.push_back( Vector2d(3,0));
00614   a.push_back( Vector2d(4,1));
00615   a.push_back( Vector2d(6,1));
00616   a.push_back( Vector2d(8,0));
00617   a.push_back( Vector2d(12,0));
00618   a.push_back( Vector2d(13,2));
00619   a.push_back( Vector2d(8,2));
00620   a.push_back( Vector2d(8,4));
00621   a.push_back( Vector2d(11,4));
00622   a.push_back( Vector2d(11,6));
00623   a.push_back( Vector2d(6,6));
00624   a.push_back( Vector2d(4,3));
00625   a.push_back( Vector2d(2,6));
00626 
00627   // allocate an STL vector to hold the answer.
00628 
00629   Vector2dVector result;
00630 
00631   //  Invoke the triangulator to triangulate this polygon.
00632   Triangulate::Process(a,result);
00633 
00634   // print out the results.
00635   int tcount = result.size()/3;
00636 
00637   for (int i=0; i<tcount; i++)
00638   {
00639     const Vector2d &p1 = result[i*3+0];
00640     const Vector2d &p2 = result[i*3+1];
00641     const Vector2d &p3 = result[i*3+2];
00642     printf("Triangle %d => (%0.0f,%0.0f) (%0.0f,%0.0f) (%0.0f,%0.0f)\n",i+1,
00643     p1.GetX(),p1.GetY(),p2.GetX(),p2.GetY(),p3.GetX(),p3.GetY());
00644   }
00645 
00646 }
00647 
00648 
00649 #endif
00650