00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
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
00102
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
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
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)
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 ;
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 ;
00135 else
00136 return Independent ;
00137 }
00138
00139
00140
00141 int PrimitivePositioning::computeRelativePosition(const Polygone *Q,const Point *P)
00142 {
00143 if(pointOutOfPolygon_XY(P->vertex(0),Q,(double)_EPS))
00144 return Independent ;
00145
00146
00147
00148 if(Q->equation(P->vertex(0)) >= 0)
00149 return Upper ;
00150 else
00151 return Lower ;
00152 }
00153
00154
00155
00156 int PrimitivePositioning::computeRelativePosition(const Polygone *P,const Segment *S)
00157 {
00158
00159
00160
00161
00162
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
00176
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
00191
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)
00204 res = Upper ;
00205
00206 return res ;
00207 }
00208
00209
00210
00211 int PrimitivePositioning::computeRelativePosition(const Polygone *P1,const Polygone *P2)
00212 {
00213
00214
00215
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 ;
00232 }
00233
00234 int res = Independent ;
00235
00236 if (gpc_int.num_contours != 1)
00237 {
00238 gpc_free_polygon(&gpc_int) ;
00239 return res ;
00240
00241 }
00242
00243
00244
00245
00246
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
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
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
00294
00295
00296
00297
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++)
00308 {
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))
00319 return false ;
00320 else
00321 return true ;
00322 }
00323
00324 int PrimitivePositioning::inverseRP(int pos)
00325 {
00326
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
00341
00342
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)))
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
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 ; }
00520 if(Smin == 1) { P_plus = P ; P_moins = NULL ; return ; }
00521 if(Smax == -1) { P_plus = NULL ; P_moins = P ; return ; }
00522
00523 if((Smin == -1)&&(Smax == 0)) { P_plus = NULL ; P_moins = P ; return ; }
00524 if((Smin == 0)&&(Smax == 1)) { P_plus = P ; P_moins = NULL ; return ; }
00525
00526
00527
00528 vector<Feedback3DColor> Ps ;
00529 vector<Feedback3DColor> Ms ;
00530
00531
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
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
00565
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 }
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
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 ; }
00651 if(Smin == 1) { P_plus = S ; P_moins = NULL ; return ; }
00652 if(Smax == -1) { P_plus = NULL ; P_moins = S ; return ; }
00653
00654 if((Smin == -1)&&(Smax == 0)) { P_plus = NULL ; P_moins = S ; return ; }
00655 if((Smin == 0)&&(Smax == 1)) { P_plus = S ; P_moins = NULL ; return ; }
00656
00657
00658
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
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
00703
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