PrimitivePositioning.cpp
Go to the documentation of this file.
00001 /*
00002  This file is part of the VRender library.
00003  Copyright (C) 2005 Cyril Soler (Cyril.Soler@imag.fr)
00004  Version 1.0.0, released on June 27, 2005.
00005 
00006  http://artis.imag.fr/Members/Cyril.Soler/VRender
00007 
00008  VRender 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  VRender 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 for more details.
00017 
00018  You should have received a copy of the GNU General Public License
00019  along with VRender; if not, write to the Free Software Foundation, Inc.,
00020  51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
00021 */
00022 
00023 /****************************************************************************
00024 
00025  Copyright (C) 2002-2013 Gilles Debunne. All rights reserved.
00026 
00027  This file is part of the QGLViewer library version 2.4.0.
00028 
00029  http://www.libqglviewer.com - contact@libqglviewer.com
00030 
00031  This file may be used under the terms of the GNU General Public License 
00032  versions 2.0 or 3.0 as published by the Free Software Foundation and
00033  appearing in the LICENSE file included in the packaging of this file.
00034  In addition, as a special exception, Gilles Debunne gives you certain 
00035  additional rights, described in the file GPL_EXCEPTION in this package.
00036 
00037  libQGLViewer uses dual licensing. Commercial/proprietary software must
00038  purchase a libQGLViewer Commercial License.
00039 
00040  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00041  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00042 
00043 *****************************************************************************/
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 
00078 
00079 
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088 #include "Primitive.h"
00089 #include "AxisAlignedBox.h"
00090 #include "PrimitivePositioning.h"
00091 #include "math.h"
00092 #include "Vector2.h"
00093 
00094 using namespace vrender ;
00095 using namespace std ;
00096 
00097 #define DEBUG_TS
00098 
00099 double PrimitivePositioning::_EPS = 0.00001 ;
00100 
00101 // Computes relative position of the second primitive toward the first.
00102 // As a general rule, the smaller the Z of a primitive, the Upper the primitive.
00103 
00104 int PrimitivePositioning::computeRelativePosition(const Primitive *p1,const Primitive *p2)
00105 {
00106         AxisAlignedBox_xyz bb1(p1->bbox()) ;
00107         AxisAlignedBox_xyz bb2(p2->bbox()) ;
00108 
00109         // 1 - check if bounding boxes are disjoint. In such a case, a rapid answer is possible.
00110 
00111         if( bb1.maxi().x() < bb2.mini().x() || bb1.mini().x() > bb2.maxi().x()) return Independent ;
00112         if( bb1.maxi().y() < bb2.mini().y() || bb1.mini().y() > bb2.maxi().y()) return Independent ;
00113 
00114         // 2 - call specific tests for each case.
00115 
00116         if(p1->nbVertices() >= 3)
00117                 if(p2->nbVertices() >= 3)
00118                         return computeRelativePosition( dynamic_cast<const Polygone *>(p1),dynamic_cast<const Polygone *>(p2)) ;
00119                 else if(p2->nbVertices() == 2) // Case of a segment versus a polygon
00120                         return computeRelativePosition( dynamic_cast<const Polygone *>(p1),dynamic_cast<const Segment *>(p2)) ;
00121                 else
00122                         return computeRelativePosition( dynamic_cast<const Polygone *>(p1),dynamic_cast<const Point *>(p2)) ;
00123         else if(p1->nbVertices() == 2)
00124                 if(p2->nbVertices() >= 3)
00125                         return inverseRP(computeRelativePosition( dynamic_cast<const Polygone *>(p2),dynamic_cast<const Segment *>(p1))) ;
00126                 else if(p2->nbVertices() == 2)
00127                         return computeRelativePosition( dynamic_cast<const Segment *>(p1),dynamic_cast<const Segment *>(p2)) ;
00128                 else
00129                         return Independent ;    // segment vs point => independent
00130         else
00131                 if(p2->nbVertices() >= 3)
00132                         return inverseRP(computeRelativePosition( dynamic_cast<const Polygone *>(p2),dynamic_cast<const Point *>(p1))) ;
00133                 else if(p2->nbVertices() == 2)
00134                         return Independent ;    // point vs segment => independent
00135                 else
00136                         return Independent ;    // point vs point => independent
00137 }
00138 
00139 // Computes the relative position of the point toward a *convex* polygon.
00140 
00141 int PrimitivePositioning::computeRelativePosition(const Polygone *Q,const Point *P)
00142 {
00143         if(pointOutOfPolygon_XY(P->vertex(0),Q,(double)_EPS)) // On met un eps > 0, pour que les
00144                 return Independent ;                                                     // points du bords soient inclus dans le polygone.
00145 
00146         // now compute the relative position of the point toward the polygon
00147 
00148         if(Q->equation(P->vertex(0)) >= 0)
00149                 return Upper ;
00150         else
00151                 return Lower ;
00152 }
00153 
00154 // Computes the relative position of the segment toward a *convex* polygon.
00155 
00156 int PrimitivePositioning::computeRelativePosition(const Polygone *P,const Segment *S)
00157 {
00158         //  Computes the intersection of the segment and the polygon in 2D, then
00159         // project the extremities of the intersection onto the segment, and compare
00160         // the points to the polygon.
00161 
00162         // 1 - 2D-intersection of segment and polygon
00163 
00164         vector<double> intersections ;
00165 
00166         if(!pointOutOfPolygon_XY(S->vertex(0),P,_EPS)) intersections.push_back(0.0);
00167         if(!pointOutOfPolygon_XY(S->vertex(1),P,_EPS)) intersections.push_back(1.0);
00168 
00169         double t1,t2 ;
00170 
00171         for(unsigned int i=0;i<P->nbVertices();++i)
00172                 if(intersectSegments_XY(Vector2(S->vertex(0)),Vector2(S->vertex(1)),Vector2(P->vertex(i)),Vector2(P->vertex(i+1)),_EPS,t1,t2))
00173                         intersections.push_back(t1) ;
00174 
00175         // 2 - Checks wether the intersection segment is reduced to a point. In this case,
00176         //      both primitives are independent.
00177 
00178         double tmin = FLT_MAX ;
00179         double tmax = -FLT_MAX ;
00180 
00181         for(unsigned int j=0;j<intersections.size();++j)
00182         {
00183                 tmin = min(tmin,intersections[j]) ;
00184                 tmax = max(tmax,intersections[j]) ;
00185         }
00186 
00187         if(tmax - tmin < 2*_EPS)
00188                 return Independent ;
00189 
00190         // 3 - The intersection segment is not reduced to a point. Compares 3D
00191         //   projections of the intersections with the plane of the polygon.
00192 
00193         int res = Independent ;
00194 
00195         for(unsigned int k=0;k<intersections.size();++k)
00196         {
00197                 Vector3 v( (1-intersections[k])*S->vertex(0) + intersections[k]*S->vertex(1) ) ;
00198 
00199                 if(P->equation(v) < -_EPS) res |= Lower ;
00200                 if(P->equation(v) >  _EPS) res |= Upper ;
00201         }
00202 
00203         if(intersections.size() > 1 && res == Independent)      // case of segments tangent to the polygon
00204                 res = Upper ;
00205 
00206         return res ;
00207 }
00208 
00209 // Computes the relative position of a polygon toward a convex polygon.
00210 
00211 int PrimitivePositioning::computeRelativePosition(const Polygone *P1,const Polygone *P2)
00212 {
00213         // 1 - use gpc to conservatively check for intersection. This works fine because
00214         //    gpc produces a null intersection for polygons sharing an edge, which
00215         //    is exactly what we need.
00216 
00217         gpc_polygon gpc_int ;
00218 
00219         try
00220         {
00221                 gpc_polygon gpc_p1 = createGPCPolygon_XY(P1) ;
00222                 gpc_polygon gpc_p2 = createGPCPolygon_XY(P2) ;
00223 
00224                 gpc_polygon_clip(GPC_INT,&gpc_p1,&gpc_p2,&gpc_int) ;
00225 
00226                 gpc_free_polygon(&gpc_p1) ;
00227                 gpc_free_polygon(&gpc_p2) ;
00228         }
00229         catch(exception&)
00230         {
00231                 return Independent ;                            // no free, because we don't really now what happenned.
00232         }
00233 
00234         int res = Independent ;
00235 
00236         if (gpc_int.num_contours != 1) // There is some numerical error in gpc. Let's skip.
00237           {
00238             gpc_free_polygon(&gpc_int) ;
00239             return res ;
00240             // throw runtime_error("Intersection with more than 1 contour ! Non convex polygons ?") ;
00241           }
00242 
00243         // 2 - polygons are not independent. Compute their relative position.
00244         //    For this, we project the vertices of the 2D intersection onto the
00245         //   support plane of each polygon. The epsilon-signs of each point toward
00246         //   both planes give the relative position of the polygons.
00247 
00248         for(int i=0;i<gpc_int.contour[0].num_vertices && (res < (Upper | Lower));++i)
00249         {
00250                 if(P1->normal().z() == 0.0) throw runtime_error("could not project point. Unexpected case !") ;
00251                 if(P2->normal().z() == 0.0) throw runtime_error("could not project point. Unexpected case !") ;
00252 
00253                 // project point onto support planes
00254 
00255                 double f1 = P1->normal().x() * gpc_int.contour[0].vertex[i].x + P1->normal().y() * gpc_int.contour[0].vertex[i].y - P1->c() ;
00256                 double f2 = P2->normal().x() * gpc_int.contour[0].vertex[i].x + P2->normal().y() * gpc_int.contour[0].vertex[i].y - P2->c() ;
00257 
00258                 Vector3 v1(gpc_int.contour[0].vertex[i].x,gpc_int.contour[0].vertex[i].y, -f1/P1->normal().z()) ;
00259                 Vector3 v2(gpc_int.contour[0].vertex[i].x,gpc_int.contour[0].vertex[i].y, -f2/P2->normal().z()) ;
00260 
00261                 if(P1->equation(v2) < -_EPS) res |= Lower ;
00262                 if(P1->equation(v2) >  _EPS) res |= Upper ;
00263                 if(P2->equation(v1) < -_EPS) res |= Upper ;
00264                 if(P2->equation(v1) >  _EPS) res |= Lower ;
00265         }
00266         gpc_free_polygon(&gpc_int) ;
00267         return res ;
00268 }
00269 
00270 // Computes the relative position of a segment toward another segment.
00271 
00272 int PrimitivePositioning::computeRelativePosition(const Segment *S1,const Segment *S2)
00273 {
00274         double t1,t2 ;
00275 
00276         if(!intersectSegments_XY(       Vector2(S1->vertex(0)),Vector2(S1->vertex(1)),
00277                                                                                 Vector2(S2->vertex(0)),Vector2(S2->vertex(1)),
00278                                                                                 -(double)_EPS,t1,t2 ))
00279                 return Independent ;
00280         else
00281         {
00282                 double z1 = (1.0 - t1)*S1->vertex(0).z() + t1*S1->vertex(1).z() ;
00283                 double z2 = (1.0 - t2)*S2->vertex(0).z() + t2*S2->vertex(1).z() ;
00284 
00285                 if(z1 <= z2)
00286                         return Lower ;
00287                 else
00288                         return Upper ;
00289         }
00290 }
00291 
00292 
00293 // Teste si le point est exterieur au polygone (convexe). Plus I_EPS est grand
00294 // plus il faut etre loin pour que ca soit vrai. EPS=0 correspond au polygone
00295 // lui-meme bords inclus. Pour EPS<0, des points interieurs pres de la frontiere sont
00296 // declares exterieurs.  Plus I_EPS est grand, plus l'ensemble des points
00297 // consideres comme interieur est dilate.
00298 
00299 bool PrimitivePositioning::pointOutOfPolygon_XY(const Vector3& P,const Polygone *Q,double I_EPS)
00300 {
00301         int nq = Q->nbVertices() ;
00302         Vector2 p = Vector2(P) ;
00303 
00304         FLOAT MaxZ = -FLT_MAX ;
00305         FLOAT MinZ =  FLT_MAX ;
00306 
00307         for(int j=0;j<nq;j++)                           //  Regarde si P.(x,y) est a l'interieur
00308         {                                       // ou a l'exterieur du polygone.
00309                 Vector2 q1 = Vector2(Q->vertex(j)) ;
00310                 Vector2 q2 = Vector2(Q->vertex(j+1)) ;
00311 
00312                 double Z = (q1-p)^(q2-p) ;
00313 
00314                 MinZ = min(Z,MinZ) ;
00315                 MaxZ = max(Z,MaxZ) ;
00316         }
00317 
00318         if((MaxZ <= -I_EPS*I_EPS)||(MinZ >= I_EPS*I_EPS))       // the point is inside the polygon
00319                 return false ;
00320         else
00321                 return true ;
00322 }
00323 
00324 int PrimitivePositioning::inverseRP(int pos)
00325 {
00326         // Basically switch bits of Lower and Upper
00327 
00328         switch(pos)
00329         {
00330                 case Independent: return Independent ;
00331                 case Lower: return Upper ;
00332                 case Upper: return Lower ;
00333                 case Upper | Lower: return Upper | Lower ;
00334                 default:
00335                                                                   throw runtime_error("Unexpected value.") ;
00336                                                                   return pos ;
00337         }
00338 }
00339 
00340 // Calcule l'intersection des segments [P1,Q1] et [P2,Q2]
00341 // En retour, (1-t1,t1) et (1-t2,t2) sont les coordonnees
00342 // barycentriques de l'intersection dans chaque segment.
00343 
00344 bool PrimitivePositioning::intersectSegments_XY(const Vector2& P1,const Vector2& Q1,
00345                                                                                                                                 const Vector2& P2,const Vector2& Q2,
00346                                                                                                                                 double I_EPS,
00347                                                                                                                                 double & t1,double & t2)
00348 {
00349         double P1x(P1.x()) ;
00350         double P1y(P1.y()) ;
00351         double P2x(P2.x()) ;
00352         double P2y(P2.y()) ;
00353         double Q1x(Q1.x()) ;
00354         double Q1y(Q1.y()) ;
00355         double Q2x(Q2.x()) ;
00356         double Q2y(Q2.y()) ;
00357 
00358         double a2 = -(Q2y - P2y) ;
00359         double b2 =  (Q2x - P2x) ;
00360         double c2 =  P2x*a2+P2y*b2 ;
00361 
00362         double a1 = -(Q1y - P1y) ;
00363         double b1 =  (Q1x - P1x) ;
00364         double c1 =  P1x*a1+P1y*b1 ;
00365 
00366         double d2 = a2*(Q1x-P1x)+b2*(Q1y-P1y) ;
00367         double d1 = a1*(Q2x-P2x)+b1*(Q2y-P2y) ;
00368 
00369         if((fabs(d2) <= fabs(I_EPS))||(fabs(d1) <= fabs(I_EPS)))        // les segments sont paralleles
00370         {
00371                 if(fabs(a2*P1x + b2*P1y - c2) >= I_EPS)
00372                         return false ;
00373 
00374                 double tP1,tQ1 ;
00375 
00376                 if(P1x != Q1x)
00377                 {
00378                         tP1 = (P2x-P1x)/(Q1x-P1x) ;
00379                         tQ1 = (Q2x-P1x)/(Q1x-P1x) ;
00380                 }
00381                 else if(P1y != Q1y)
00382                 {
00383                         tP1 = (P2y-P1y)/(Q1y-P1y) ;
00384                         tQ1 = (Q2y-P1y)/(Q1y-P1y) ;
00385                 }
00386                 else
00387                 {
00388 #ifdef DEBUG_TS
00389                         printf("IntersectSegments2D:: Error ! One segment has length 0\n") ;
00390                         printf("This special case is not treated yet.\n") ;
00391 #endif
00392                         return false ;
00393                 }
00394 
00395                 double tPQM = max(tP1,tQ1) ;
00396                 double tPQm = min(tP1,tQ1) ;
00397 
00398                 if(( tPQM < -I_EPS) || (tPQm > 1.0+I_EPS))
00399                         return false ;
00400 
00401                 if(tPQm > 0.0)
00402                 {
00403                         t1 = tPQm ;
00404                         t2 = 0.0 ;
00405                 }
00406                 else
00407                 {
00408                         t1 = 0.0 ;
00409                         if(P2x != Q2x)
00410                                 t2 = (P1x-P2x)/(Q2x-P2x) ;
00411                         else if(P2y != Q2y)
00412                                 t2 = (P1y-P2y)/(Q2y-P2y) ;
00413                         else
00414                         {
00415 #ifdef DEBUG_TS
00416                                 printf("IntersectSegments2D:: Error ! One segment has length 0\n") ;
00417                                 printf("This special case is not treated yet.\n") ;
00418 #endif
00419                                 return false ;
00420                         }
00421                 }
00422 
00423                 return true ;
00424         }
00425         else
00426         {
00427                 t2 = (c1 - a1*P2x - b1*P2y)/d1 ;
00428                 t1 = (c2 - a2*P1x - b2*P1y)/d2 ;
00429 
00430                 if((t2 > 1+I_EPS)||(t2 < -I_EPS)||(t1 > 1+I_EPS)||(t1 < -I_EPS))
00431                         return false ;
00432 
00433                 return true ;
00434         }
00435 }
00436 
00437 gpc_polygon PrimitivePositioning::createGPCPolygon_XY(const Polygone *P)
00438 {
00439         gpc_polygon p ;
00440 
00441         p.num_contours = 0 ;
00442         p.hole = NULL ;
00443         p.contour = NULL ;
00444 
00445         gpc_vertex_list *gpc_p_verts = new gpc_vertex_list ;
00446 
00447         gpc_p_verts->num_vertices = P->nbVertices() ;
00448         gpc_p_verts->vertex = new gpc_vertex[P->nbVertices()] ;
00449 
00450         for(unsigned int i=0;i<P->nbVertices();++i)
00451         {
00452                 gpc_p_verts->vertex[i].x = P->vertex(i).x() ;
00453                 gpc_p_verts->vertex[i].y = P->vertex(i).y() ;
00454         }
00455 
00456         gpc_add_contour(&p,gpc_p_verts,false) ;
00457 
00458         return p ;
00459 }
00460 
00461 void PrimitivePositioning::getsigns(const Primitive *P,const NVector3& v,double C,
00462                                                                                                 vector<int>& signs,vector<double>& zvals,int& Smin,int& Smax,double I_EPS)
00463 {
00464         if(P == NULL)
00465                 throw runtime_error("Null primitive in getsigns !") ;
00466 
00467         int n = P->nbVertices() ;
00468 
00469         Smin =  1 ;
00470         Smax = -1 ;
00471 
00472         // On classe les sommets en fonction de leur signe
00473 
00474         double zmax = -FLT_MAX ;
00475         double zmin =  FLT_MAX ;
00476         zvals.resize(n) ;
00477 
00478         for(int i=0;i<n;i++)
00479         {
00480                 double Z = P->vertex(i) * v - C ;
00481 
00482                 if(Z > zmax) zmax = Z ;
00483                 if(Z < zmin) zmin = Z ;
00484 
00485                 zvals[i] = Z ;
00486         }
00487 
00488         signs.resize(n) ;
00489 
00490         for(int j=0;j<n;j++)
00491         {
00492                 if(zvals[j] < -I_EPS)
00493                         signs[j] = -1 ;
00494                 else if(zvals[j] > I_EPS)
00495                         signs[j] = 1 ;
00496                 else
00497                         signs[j] = 0 ;
00498 
00499                 if(Smin > signs[j]) Smin = signs[j] ;
00500                 if(Smax < signs[j]) Smax = signs[j] ;
00501         }
00502 }
00503 
00504 void PrimitivePositioning::split(Polygone *P,const NVector3& v,double C,Primitive *& P_plus,Primitive *& P_moins)
00505 {
00506         vector<int> Signs ;
00507         vector<double> Zvals ;
00508 
00509         P_plus = NULL ;
00510         P_moins = NULL ;
00511 
00512         int Smin = 1 ;
00513         int Smax = -1 ;
00514 
00515         getsigns(P,v,C,Signs,Zvals,Smin,Smax,_EPS) ;
00516 
00517         int n = P->nbVertices() ;
00518 
00519         if((Smin == 0)&&(Smax == 0)){ P_moins = P ; P_plus = NULL ; return ; }  // Polygone inclus dans le plan
00520         if(Smin == 1)                                   { P_plus = P ; P_moins = NULL ; return ; }      // Polygone tout positif
00521         if(Smax == -1)                                  { P_plus = NULL ; P_moins = P ; return ; }      // Polygone tout negatif
00522 
00523         if((Smin == -1)&&(Smax == 0)) { P_plus = NULL ; P_moins = P ; return ; }        // Polygone tout negatif ou null
00524         if((Smin == 0)&&(Smax == 1))  { P_plus = P ; P_moins = NULL ; return ; }        // Polygone tout positif ou null
00525 
00526         // Reste le cas Smin = -1 et Smax = 1. Il faut couper
00527 
00528         vector<Feedback3DColor> Ps ;
00529         vector<Feedback3DColor> Ms ;
00530 
00531         // On teste la coherence des signes.
00532 
00533         int nZero = 0 ;
00534         int nconsZero = 0 ;
00535 
00536         for(int i=0;i<n;i++)
00537         {
00538                 if(Signs[i] == 0)
00539                 {
00540                         nZero++ ;
00541 
00542                         if(Signs[(i+1)%n] == 0)
00543                                 nconsZero++ ;
00544                 }
00545         }
00546 
00547         // Ils y a des imprecisions numeriques dues au fait que le poly estpres du plan.
00548         if((nZero > 2)||(nconsZero > 0)) { P_moins = P ; P_plus  = NULL ; return ; }
00549 
00550         int dep=0 ; while(Signs[dep] == 0) dep++ ;
00551         int prev_sign = Signs[dep] ;
00552 
00553         for(int j=1;j<=n;j++)
00554         {
00555                 int sign = Signs[(j+dep)%n] ;
00556 
00557                 if(sign == prev_sign)
00558                 {
00559                         if(sign ==  1) Ps.push_back(P->sommet3DColor(j+dep)) ;
00560                         if(sign == -1) Ms.push_back(P->sommet3DColor(j+dep)) ;
00561                 }
00562                 else if(sign == -prev_sign)
00563                 {
00564                         //  Il faut effectuer le calcul en utilisant les memes valeurs que pour le calcul des signes,
00565                         // sinon on risque des incoherences dues aux imprecisions numeriques.
00566 
00567                         double Z1 = Zvals[(j+dep-1)%n] ;
00568                         double Z2 = Zvals[(j+dep)%n] ;
00569 
00570                         double t = fabs(Z1/(Z2 - Z1)) ;
00571 
00572                         if((t < 0.0)||(t > 1.0))
00573                         {
00574                                 if(t > 1.0) t = 1.0 ;
00575                                 if(t < 0.0) t = 0.0 ;
00576                         }
00577                         Feedback3DColor newVertex((1-t)*P->sommet3DColor(j+dep-1) + t*P->sommet3DColor(j+dep)) ;
00578 
00579                         Ps.push_back(newVertex) ;
00580                         Ms.push_back(newVertex) ;
00581 
00582                         if(sign == 1)
00583                                 Ps.push_back(P->sommet3DColor(j+dep)) ;
00584 
00585                         if(sign == -1)
00586                                 Ms.push_back(P->sommet3DColor(j+dep)) ;
00587 
00588                         prev_sign = sign ;
00589                 } // prev_sign != 0 donc necessairement sign = 0. Le sommet tombe dans le plan
00590                 else
00591                 {
00592                         Feedback3DColor newVertex = P->sommet3DColor(j+dep) ;
00593 
00594                         Ps.push_back(newVertex) ;
00595                         Ms.push_back(newVertex) ;
00596 
00597                         prev_sign = -prev_sign ;
00598                 }
00599         }
00600 
00601         if(Ps.size() > 100 || Ms.size() > 100 )
00602                 printf("Primitive::split: Error. nPs = %d, nMs = %d.\n",int(Ps.size()),int(Ms.size())) ;
00603 
00604         // on suppose pour l'instant que les polygones sont convexes
00605 
00606         if(Ps.size() == 1)
00607                 P_plus = new Point(Ps[0]) ;
00608         else if(Ps.size() == 2)
00609                 P_plus = new Segment(Ps[0],Ps[1]) ;
00610         else
00611                 P_plus  = new Polygone(Ps) ;
00612 
00613         if(Ms.size() == 1)
00614                 P_moins = new Point(Ms[0]) ;
00615         else if(Ms.size() == 2)
00616                 P_moins = new Segment(Ms[0],Ms[1]) ;
00617         else
00618                 P_moins = new Polygone(Ms) ;
00619 }
00620 
00621 void PrimitivePositioning::split(Point *P,const NVector3& v,double C,Primitive * & P_plus,Primitive * & P_moins)
00622 {
00623         if(v*P->vertex(0)-C > -_EPS)
00624         {
00625                 P_plus = P ;
00626                 P_moins = NULL ;
00627         }
00628         else
00629         {
00630                 P_moins = P ;
00631                 P_plus = NULL ;
00632         }
00633 }
00634 
00635 void PrimitivePositioning::split(Segment *S,const NVector3& v,double C,Primitive * & P_plus,Primitive * & P_moins)
00636 {
00637         vector<int> Signs ;
00638         vector<double> Zvals ;
00639 
00640         P_plus = NULL ;
00641         P_moins = NULL ;
00642 
00643         int Smin = 1 ;
00644         int Smax = -1 ;
00645 
00646         getsigns(S,v,C,Signs,Zvals,Smin,Smax,_EPS) ;
00647 
00648         int n = S->nbVertices() ;
00649 
00650         if((Smin == 0)&&(Smax == 0))    { P_moins = S ; P_plus = NULL ; return ; }      // Polygone inclus dans le plan
00651         if(Smin == 1)                                           { P_plus = S ; P_moins = NULL ; return ; }      // Polygone tout positif
00652         if(Smax == -1)                                  { P_plus = NULL ; P_moins = S ; return ; }      // Polygone tout negatif
00653 
00654         if((Smin == -1)&&(Smax == 0)) { P_plus = NULL ; P_moins = S ; return ; }        // Polygone tout negatif ou null
00655         if((Smin == 0)&&(Smax == 1))  { P_plus = S ; P_moins = NULL ; return ; }        // Polygone tout positif ou null
00656 
00657         // Reste le cas Smin = -1 et Smax = 1. Il faut couper
00658         // On teste la coherence des signes.
00659 
00660         int nZero = 0 ;
00661         int nconsZero = 0 ;
00662 
00663         for(int i=0;i<n;i++)
00664         {
00665                 if(Signs[i] == 0)
00666                 {
00667                         nZero++ ;
00668 
00669                         if(Signs[(i+1)%n] == 0)
00670                                 nconsZero++ ;
00671                 }
00672         }
00673 
00674         // Ils y a des imprecisions numeriques dues au fait que le poly estpres du plan.
00675         if((nZero > 2)||(nconsZero > 0)) { P_moins = S ; P_plus  = NULL ; return ; }
00676 
00677         double Z1 = Zvals[0] ;
00678         double Z2 = Zvals[1] ;
00679 
00680         double t = fabs(Z1/(Z2 - Z1)) ;
00681 
00682         if((t < 0.0)||(t > 1.0))
00683         {
00684                 if(t > 1.0) t = 1.0 ;
00685                 if(t < 0.0) t = 0.0 ;
00686         }
00687 
00688         Feedback3DColor newVertex = S->sommet3DColor(0) * (1-t) + S->sommet3DColor(1) * t ;
00689 
00690         if(Signs[0] < 0)
00691         {
00692                 P_plus = new Segment(newVertex,S->sommet3DColor(1)) ;
00693                 P_moins = new Segment(S->sommet3DColor(0),newVertex) ;
00694         }
00695         else
00696         {
00697                 P_plus = new Segment(S->sommet3DColor(0),newVertex) ;
00698                 P_moins = new Segment(newVertex,S->sommet3DColor(1)) ;
00699         }
00700 }
00701 
00702 // splits primitive P by plane of equation v.X=c. The upper part is setup in a new primitive called prim_up and
00703 // the lower part is in prim_lo.
00704 
00705 void PrimitivePositioning::splitPrimitive(Primitive *P,const NVector3& v,double c, Primitive *& prim_up,Primitive *& prim_lo)
00706 {
00707         Polygone *p1 = dynamic_cast<Polygone *>(P) ; if(p1 != NULL) PrimitivePositioning::split(p1,v,c,prim_up,prim_lo) ;
00708         Segment  *p2 = dynamic_cast<Segment  *>(P) ; if(p2 != NULL) PrimitivePositioning::split(p2,v,c,prim_up,prim_lo) ;
00709         Point    *p3 = dynamic_cast<Point    *>(P) ; if(p3 != NULL) PrimitivePositioning::split(p3,v,c,prim_up,prim_lo) ;
00710 }
00711 


octovis
Author(s): Kai M. Wurm , Armin Hornung
autogenerated on Thu Jun 6 2019 17:31:58