Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

IGPolygon.cpp

Go to the documentation of this file.
00001 /* $Id: IGPolygon.cpp,v 1.1 2001/05/27 15:25:28 formella Exp $ */
00002 
00003 /*
00004  *  Copyright (C) 2001, Dr. Arno Formella
00005  *                      Universidade de Vigo
00006  *                      Departamento de Informatica
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License
00017  *          http://www.gnu.ai.mit.edu/copyleft/gpl.html
00018  *  for more details.
00019  */
00020 
00021 #include <assert.h>
00022 
00023 #include "IGPolygon.h"
00024 
00025 IGPolygon::IGPolygon(
00026 ) :
00027   okForOpenGL(false)
00028 {
00029 }
00030 
00031 IGPolygon::IGPolygon(
00032   const IGPolygon& P
00033 ) :
00034   corners(P.corners),
00035   center(P.center),
00036   normal(P.normal),
00037   okForOpenGL(P.okForOpenGL)
00038 {
00039 }
00040 
00041 IGPolygon::~IGPolygon(
00042 ) {
00043 }
00044 
00045 IGPolygon& IGPolygon::operator=(
00046   const IGPolygon& P
00047 ) {
00048   if(this!=&P) {
00049     corners    =P.corners;
00050     center     =P.center;
00051     normal     =P.normal;
00052     okForOpenGL=P.okForOpenGL;
00053   }
00054   return(*this);
00055 }
00056 
00057 void IGPolygon::CheckForOpenGL(
00058 ) {
00059   okForOpenGL=false;
00060   // a polygon must have at least three corners
00061   // we need not to warry about multiple points, everything will work fine too
00062   if(corners.size()<3) return;
00063   ComputeCenter();
00064   if(ComputeNormal()) {
00065     if(PointsInPlane()) {
00066       list<point> L;
00067       IGPoint p;
00068       // we look for the largest projection, that is the one given
00069       // by the maximum absolut component of the normal vector
00070       if(fabs(normal[0])>=fabs(normal[1])&&
00071          fabs(normal[0])>=fabs(normal[2])) {
00072         // the maximum is the x-coordinate, hence the plane is yz
00073         forall(p,corners) L.append(p.project_yz());
00074       }
00075       else if(fabs(normal[1])>=fabs(normal[0])&&
00076               fabs(normal[1])>=fabs(normal[2])) {
00077         // the maximum is the y-coordinate, hence the plane is xz
00078         forall(p,corners) L.append(p.project_xz());
00079       }
00080       else {
00081         // the maximum is the z-coordinate, hence the plane is xy
00082         forall(p,corners) L.append(p.project_xy());
00083       }
00084       if(IsSimpleAndConvex(L)) okForOpenGL=true;
00085       else {
00086         cout << "non simple-and-convex polygon found\n";
00087       }
00088     }
00089   }
00090 }
00091 
00092 double IGPolygon::ComputeArea(
00093   const list<point>& L
00094 ) const {
00095   double    area(0.0);
00096   list_item it(L.first());
00097   list_item jt(L.succ(it));
00098   // we apply the formula for the weighted area
00099   for(int i(L.size()); i>0; i--) {
00100     area+=L[it].xcoord()*L[jt].ycoord()-L[jt].xcoord()*L[it].ycoord();
00101     it=jt;
00102     jt=L.cyclic_succ(jt);
00103   }
00104   return area;
00105 }
00106 
00107 void IGPolygon::ComputeCenter(
00108 ) {
00109   assert(!corners.empty());
00110   IGPoint  p;
00111   d3_point o;
00112   // we apply the formula for the center
00113   forall(p,corners) o=o+p.to_vector();
00114   center=d3_point(o.to_vector()*(1.0/corners.size()));
00115 }
00116 
00117 bool IGPolygon::ComputeNormal(
00118 ) {
00119   IGPoint     p;
00120   list<point> P;
00121   // we compute the (weighted) area in all three projections
00122   forall(p,corners) P.append(p.project_xy());
00123   double A_xy(ComputeArea(P));
00124 
00125   P.clear();
00126   forall(p,corners) P.append(p.project_xz());
00127   double A_xz(ComputeArea(P));
00128 
00129   P.clear();
00130   forall(p,corners) P.append(p.project_yz());
00131   double A_yz(ComputeArea(P));
00132 
00133   // if all areas are too small, the points are either collinear
00134   // or they define a non-simple polygon with weighted area of zero
00135   double epsilon(0.0001);
00136   if(fabs(A_xy)<epsilon&&
00137      fabs(A_xz)<epsilon&&
00138      fabs(A_yz)<epsilon
00139     ) {
00140     cout << "polygon with almost zero normal found\n";
00141     return false;
00142   }
00143   // we compute the normal applying the formula
00144   normal=vector(A_yz,-A_xz,A_xy).norm();
00145   return true;
00146 }
00147 
00148 void IGPolygon::Draw(
00149 ) const {
00150   glBegin(GL_POLYGON);
00151   IGPoint p;
00152   // we just draw all the corners of the polygon
00153   forall(p,corners) p.Draw();
00154   glEnd();
00155 }
00156 
00157 bool IGPolygon::IsBitonic(
00158   const list<double>& L
00159 ) const {
00160   // we first search for the minimum value in the list
00161   list_item it(L.min());
00162   list_item jt;
00163   bool up(true);
00164   // we check if we climb only once upstairs
00165   for(int i(L.size()); i>0; i--) {
00166     jt=L.cyclic_succ(it);
00167     if(up) {
00168       if(L[jt]<L[it]) up=false;
00169     }
00170     else if(L[jt]>L[it]) return false;
00171     it=L.cyclic_succ(it);
00172   }
00173   return true;
00174 }
00175 
00176 bool IGPolygon::IsSimpleAndConvex(
00177   const list<point>& L
00178 ) const {
00179   list<double> C;  // list of coordinates
00180   point p;
00181   // the polygon is simle-and-convex iff both the sequence of x-coordinates
00182   // and the sequence of y-coordinates are bitonic
00183   forall(p,L) C.append(p.xcoord());
00184   if(!IsBitonic(C)) return false;
00185   C.clear();
00186   forall(p,L) C.append(p.ycoord());
00187   if(!IsBitonic(C)) return false;
00188   return true;
00189 }
00190 
00191 bool IGPolygon::PointsInPlane(
00192 ) const {
00193   IGPoint p;
00194   forall(p,corners) {
00195     // we check the distance to the plane given by the normal and the center
00196     // the formula works as well in the case that p is equal to center
00197     if(fabs(normal*(p.to_vector()-center.to_vector()))>0.001) {
00198       cout << "corners are not sufficiently close to the plane\n";
00199       return false;
00200     }
00201   }
00202   return true;
00203 }
00204 
00205 istream& operator>>(
00206   istream& in,
00207   IGPolygon& P
00208 ) {
00209   int     n;
00210   IGPoint p;
00211 
00212   P.corners.clear();
00213   P.okForOpenGL=false;
00214   in >> n;
00215   assert(n>0);
00216   for(int i(0); i<n; i++) {
00217     in >> p;
00218     P.corners.append(p);
00219   }
00220   P.CheckForOpenGL();
00221   return(in);
00222 }
00223 
00224 ostream& operator<<(
00225   ostream& out,
00226   const IGPolygon& P
00227 ) {
00228   out << "Polygon: " << P.corners.size() << endl;
00229   out << "okForOpenGL: " << P.okForOpenGL << endl;
00230   out << "center: " << P.center << endl;
00231   out << "normal: " << P.normal << endl;
00232   IGPoint p;
00233   forall(p,P.corners) out << p;
00234   return(out);
00235 }
00236 

Generated at Wed May 30 11:16:28 2001 for Computer Graphics Course by doxygen1.1.5 written by Dimitri van Heesch, © 1997-2000