BWAPI
|
00001 // Copyright (c) 1997-2002 Max-Planck-Institute Saarbruecken (Germany). 00002 // All rights reserved. 00003 // 00004 // This file is part of CGAL (www.cgal.org); you may redistribute it under 00005 // the terms of the Q Public License version 1.0. 00006 // See the file LICENSE.QPL distributed with CGAL. 00007 // 00008 // Licensees holding a valid commercial license may use this file in 00009 // accordance with the commercial license agreement provided with the software. 00010 // 00011 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00012 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00013 // 00014 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Nef_S2/include/CGAL/Nef_S2/sphere_predicates.h $ 00015 // $Id: sphere_predicates.h 40851 2007-11-09 15:27:44Z ameyer $ 00016 // 00017 // 00018 // Author(s) : Michael Seel <seel@mpi-sb.mpg.de> 00019 00020 #ifndef CGAL_SPHERE_PREDICATES_H 00021 #define CGAL_SPHERE_PREDICATES_H 00022 00023 #include <CGAL/basic.h> 00024 #undef CGAL_NEF_DEBUG 00025 #define CGAL_NEF_DEBUG 23 00026 #include <CGAL/Nef_2/debug.h> 00027 #include <vector> 00028 00029 #undef CGAL_forall_iterators 00030 #define CGAL_forall_iterators(x,L)\ 00031 for(x = (L).begin(); x != (L).end(); ++x) 00032 00033 00034 CGAL_BEGIN_NAMESPACE 00035 00036 /* |spherical_orientation| takes three points of one hemisphere and 00037 returns the orientation of $p_3$ with respect to the halfcircle 00038 through $p_1$ and $p_2$. We map this to the 3d orientation predicate 00039 of the origin, $p_1$, $p_2$, and $p_3$ */ 00040 00041 template <class R> 00042 int spherical_orientation(const Sphere_point<R>& p1, 00043 const Sphere_point<R>& p2, 00044 const Sphere_point<R>& p3) 00045 { return CGAL::orientation(typename R::Point_3(0,0,0), 00046 (typename R::Point_3)p1, 00047 (typename R::Point_3)p2, 00048 (typename R::Point_3)p3); } 00049 00050 00051 /* |spherical_compare| codes our order of points during the sweep. The 00052 south pole is the first point, the north pole is the last point, then 00053 we order lexicographically. We cover the special case where both 00054 points are part of the equator first. Otherwise we sort according to 00055 the angle of the halfcircle through $S$, $N$, and the points with 00056 respect to the xy-plane. If both lie on the same halfcircle then the 00057 angle with respect to $OS$ decides. The parameter $pos=1$ does 00058 everthing in the positive halfsphere. If $pos=-1$ then we rotate the 00059 whole scenery around the y-axis by $\pi$. Then the x-axis points left 00060 and the z-axis into the equatorial plane. */ 00061 00062 template <class R> 00063 bool is_south(const Sphere_point<R>& p, int axis) { 00064 if(axis==1) 00065 return (p.hz() > 0 && 00066 p.hx() == 0 && 00067 p.hy() == 0); 00068 00069 return (p.hy() < 0 && 00070 p.hx() == 0 && 00071 p.hz() == 0); 00072 } 00073 00074 template <class R> 00075 bool is_north(const Sphere_point<R>& p, int axis) { 00076 if(axis==1) 00077 return (p.hz() < 0 && 00078 p.hx() == 0 && 00079 p.hy() == 0); 00080 00081 return (p.hy() > 0 && 00082 p.hx() == 0 && 00083 p.hz() == 0); 00084 } 00085 00086 template <class R> 00087 int spherical_compare(const Sphere_point<R>& p1, 00088 const Sphere_point<R>& p2, 00089 int axis, int pos) { 00090 00091 Sphere_point<R> pS, pN; 00092 CGAL_assertion(axis>=0 && axis<=2); 00093 switch(axis) { 00094 case 0: 00095 pS=Sphere_point<R>(0,-1,0); 00096 // pN=Sphere_point<R>(0,1,0); 00097 break; 00098 case 1: 00099 pS=Sphere_point<R>(0,0,1); 00100 // pN=Sphere_point<R>(0,0,-1); 00101 break; 00102 case 2: 00103 pS=Sphere_point<R>(0,-1,0); 00104 // pN=Sphere_point<R>(0,1,0); 00105 break; 00106 } 00107 typename R::Direction_3 00108 d1(p1-CGAL::ORIGIN), 00109 d2(p2-CGAL::ORIGIN); 00110 if (d1 == d2) return 0; 00111 if(is_south(p1,axis) || is_north(p2,axis)) return -1; 00112 if(is_south(p2,axis) || is_north(p1,axis)) return 1; 00113 // if (d1 == dS || d2 == dN) return -1; 00114 // if (d1 == dN || d2 == dS) return 1; 00115 // now no more special cases 00116 if (axis==0 && (p1.hx()==static_cast<typename R::RT>(0) && 00117 p2.hx()==static_cast<typename R::RT>(0))) { 00118 int s1 = CGAL_NTS sign(p1.hz()); 00119 int s2 = CGAL_NTS sign(p2.hz()); 00120 if ( s1 != s2 ) return pos * -s1; 00121 // now s1 == s2 00122 return -s1 * CGAL::spherical_orientation(p1,Sphere_point<R>(1,0,0),p2); 00123 } else 00124 if (axis==1 && (p1.hy()==static_cast<typename R::RT>(0) && 00125 p2.hy()==static_cast<typename R::RT>(0))) { 00126 int s1 = CGAL_NTS sign(p1.hx()); 00127 int s2 = CGAL_NTS sign(p2.hx()); 00128 if ( s1 != s2 ) return pos * s1; 00129 // now s1 == s2 00130 return s1 * CGAL::spherical_orientation(p1,Sphere_point<R>(0,1,0),p2); 00131 } else 00132 if (axis==2 && (p1.hz()==static_cast<typename R::RT>(0) && 00133 p2.hz()==static_cast<typename R::RT>(0))) { 00134 int s1 = CGAL_NTS sign(p1.hx()); 00135 int s2 = CGAL_NTS sign(p2.hx()); 00136 if ( s1 != s2 ) return pos * s1; 00137 // now s1 == s2 00138 return s1 * CGAL::spherical_orientation(p1,Sphere_point<R>(0,0,1),p2); 00139 } 00140 int sor = CGAL::spherical_orientation(pS,p1,p2); 00141 if ( sor ) return sor; 00142 if(axis==0) 00143 return CGAL::spherical_orientation(Sphere_point<R>(0,0,pos),p2,p1); 00144 return CGAL::spherical_orientation(Sphere_point<R>(-pos,0,0),p2,p1); 00145 } 00146 00147 /* the next two functions partition the segments in a list into a list 00148 that carries the segment parts that are only part of a halfspace. 00149 Halfcircles are again divided into two equally sized pieces. */ 00150 00151 template <class R, class I> 00152 void partition(const Sphere_circle<R>& c, I start, I beyond, 00153 std::list< Sphere_segment<R> >& Lpos) 00154 { CGAL_NEF_TRACEN("partition "); 00155 Sphere_segment<R> s1,s2,s3; 00156 while ( start != beyond ) { CGAL_NEF_TRACEN(" "<<*start); 00157 int i = start->intersection(c,s1,s2); 00158 if (i>1) Lpos.push_back(s2); 00159 if (i>0) Lpos.push_back(s1); 00160 ++start; 00161 } 00162 } 00163 00164 template <class R, class I> 00165 void partition_xy(I start, I beyond, 00166 std::list< Sphere_segment<R> >& L, int pos) 00167 { 00168 Sphere_circle<R> xy_circle(0,0,1), yz_circle(1,0,0); 00169 Sphere_point<R> S(0,-1,0),N(0,1,0); 00170 Sphere_segment<R> s1,s2; 00171 if (pos > 0) partition(xy_circle,start,beyond,L); 00172 else partition(xy_circle.opposite(),start,beyond,L); 00173 typename std::list< Sphere_segment<R> >::iterator it,itl; 00174 CGAL_NEF_TRACEN("partition_xy "); 00175 CGAL_forall_iterators(it,L) { 00176 CGAL_NEF_TRACEN(" "<<*it); 00177 if ( equal_as_sets(it->sphere_circle(),xy_circle) ) { 00178 CGAL_NEF_TRACEN(" splitting xy seg "<<*it); 00179 int n1 = it->intersection(yz_circle,s1,s2); 00180 if (n1 > 1 && !s2.is_degenerate()) L.insert(it,s2); 00181 if (n1 > 0 && !s1.is_degenerate()) L.insert(it,s1); 00182 int n2 = it->intersection(yz_circle.opposite(),s1,s2); 00183 if (n2 > 1 && !s2.is_degenerate()) L.insert(it,s2); 00184 if (n2 > 0 && !s1.is_degenerate()) L.insert(it,s1); 00185 itl = it; --it; L.erase(itl); 00186 // at least one item was appended 00187 } 00188 } 00189 CGAL_forall_iterators(it,L) { 00190 if ( it->is_halfcircle() ) { 00191 CGAL_NEF_TRACEN(" splitting halfcircle "<<*it); 00192 Sphere_segment<R> s1,s2; 00193 it->split_halfcircle(s1,s2); 00194 *it = s2; L.insert(it,s1); 00195 } 00196 } 00197 // append 4 xy-equator segments: 00198 Sphere_segment<R> sp(S,N,xy_circle); 00199 Sphere_segment<R> sm(S,N,xy_circle.opposite()); 00200 Sphere_segment<R> s[4]; 00201 sp.split_halfcircle(s[0],s[1]); 00202 sm.split_halfcircle(s[2],s[3]); 00203 L.insert(L.end(),s,s+4); 00204 } 00205 00206 00207 /* |intersection| calculates the intersection of a halfspace $h$ 00208 (defined via a great circle $c$) with a sphere segment 00209 $s$. Interesting are the boundary cases. If an endpoint is part of 00210 $h^0$, but the part of $s$ incident to the endpoint is not part of 00211 $h^{0+}$ then we return a trivial segment. 00212 00213 */ 00214 00215 /* 00216 template <typename R> 00217 int Sphere_segment<R>:: 00218 intersection(const CGAL::Sphere_circle<R>& c, std::vector<Sphere_segment<R> >& s) const { 00219 00220 CGAL_NEF_TRACEN(" intersection "<<*this<<" "<<c); 00221 if ( is_degenerate() ) { 00222 CGAL_NEF_TRACEN(" degenerate"); 00223 s.push_back(*this); 00224 return 1; 00225 } 00226 00227 CGAL::Oriented_side or1 = c.oriented_side(source()); 00228 CGAL::Oriented_side or2 = c.oriented_side(target()); 00229 00230 CGAL_NEF_TRACEN(" Orientation " << or1 << " " << or2); 00231 00232 if ( or1 == CGAL::opposite(or2) && or1 != or2 ) { 00233 // it is sure that $s$ intersects $h$ in its interior. the 00234 // question is which part is in the halfspace $h^+$. 00235 CGAL_NEF_TRACEN(" opposite"); 00236 Sphere_point<R> i1 = CGAL::intersection(ptr()->c_,c); 00237 if ( !has_on(i1) ) 00238 i1 = i1.antipode(); 00239 s.push_back(Sphere_segment<R>(source(),i1,sphere_circle())); 00240 s.push_back(Sphere_segment<R>(i1,target(),sphere_circle())); 00241 return 2; 00242 } 00243 else if ( or1 == CGAL::ON_ORIENTED_BOUNDARY && 00244 or2 == CGAL::ON_ORIENTED_BOUNDARY ) { 00245 // if both ends of $s$ are part of $h$ then $s$ is a halfcircle or 00246 // $s$ is fully part of $h$. In this case we have to check if the 00247 // halfcircle is not part of $h^-$. This can be formulated by an 00248 // orientation test of the point $p$ at the tip of the normal of 00249 // |s.sphere_circle()| with respect to the plane through the 00250 // endpoints of $s$ and the tip of the normal of $h$. 00251 CGAL_NEF_TRACEN(" both in plane"); 00252 s.push_back(*this); 00253 return 1; 00254 } 00255 else if ( or1 != CGAL::ON_NEGATIVE_SIDE && 00256 or2 != CGAL::ON_NEGATIVE_SIDE ) { 00257 // this case covers the endpoints of $s$ as part of the closed 00258 // oriented halfspace $h^{0+}$. At least one is part of 00259 // $h^{+}$. If $s$ is not long then the segment must be fully part 00260 // of $h^{0+}$. Otherwise if $s$ is long, then we at both ends 00261 // there are subsegments as part of $h^{0+}$ (one might be 00262 // degenerate). 00263 if ( is_long() ) { 00264 Sphere_point<R> i1 = CGAL::intersection(ptr()->c_,c); 00265 Sphere_point<R> i2 = i1.antipode(); 00266 Sphere_segment<R> so(i1,i2,sphere_circle()); 00267 if ( so.has_on(source()) && so.has_on(target()) ) 00268 std::swap(i1,i2); 00269 // now source(),i1,i2,target() are circularly ordered 00270 s.push_back(Sphere_segment(source(),i1,sphere_circle())); 00271 s.push_back(Sphere_segment(i1,i2,sphere_circle())); 00272 s.push_back(Sphere_segment(i2,target(),sphere_circle())); 00273 // CGAL_NEF_TRACEN(" both >= plane, long "<<s1<<s2); 00274 return 3; 00275 } // now short: 00276 CGAL_NEF_TRACEN(" both >= plane, short "); 00277 s.push_back(*this); 00278 return 1; 00279 } 00280 else if ( or1 != CGAL::ON_POSITIVE_SIDE && 00281 or2 != CGAL::ON_POSITIVE_SIDE ) { 00282 // either both endpoints of $s$ are in $h^-$ or one is in $h^-$ 00283 // and one on $h^0$. 00284 if ( is_long() ) { 00285 Sphere_point<R> i1 = CGAL::intersection(ptr()->c_,c); 00286 Sphere_point<R> i2 = i1.antipode(); 00287 Sphere_segment so(i1,i2,sphere_circle()); 00288 // CGAL_NEF_TRACEN(" both <= plane, long"<<so); 00289 if ( so.has_on(source()) && so.has_on(target()) ) 00290 { so = so.complement(); } 00291 // CGAL_NEF_TRACEN(" both <= plane, long"<<so); 00292 s.push_back(Sphere_segment(source(),so.source(),sphere_circle())); 00293 s.push_back(so); 00294 s.push_back(Sphere_segment(so.target(),target(),sphere_circle())); 00295 return 3; 00296 } // now short 00297 CGAL_NEF_TRACEN(" both <= plane, short"); 00298 s.push_back(*this); 00299 return 1; 00300 } 00301 00302 CGAL_error_msg("Oops, forgot some case."); 00303 return -1; 00304 } 00305 */ 00306 00307 template <typename R> 00308 int Sphere_segment<R>:: 00309 intersection(const CGAL::Sphere_circle<R>& c, 00310 Sphere_segment<R>& s1, Sphere_segment<R>& s2) const 00311 { 00312 CGAL_NEF_TRACEN(" intersection "<<*this<<" "<<c); 00313 if ( is_degenerate() ) { CGAL_NEF_TRACEN(" degenerate"); 00314 if ( !c.has_on_negative_side(source()) ) 00315 { s1 = *this; return 1; } 00316 return 0; 00317 } 00318 CGAL::Oriented_side or1 = c.oriented_side(source()); 00319 CGAL::Oriented_side or2 = c.oriented_side(target()); 00320 if ( or1 == CGAL::opposite(or2) && or1 != or2 ) { 00321 // it is sure that $s$ intersects $h$ in its interior. the 00322 // question is which part is in the halfspace $h^+$. 00323 CGAL_NEF_TRACEN(" opposite"); 00324 Sphere_point<R> i1 = CGAL::intersection(this->ptr()->c_,c); 00325 if ( !has_on(i1) ) i1 = i1.antipode(); 00326 if ( or1 == CGAL::ON_POSITIVE_SIDE ) 00327 s1 = Sphere_segment<R>(source(),i1,sphere_circle()); 00328 else if ( or2 == CGAL::ON_POSITIVE_SIDE ) 00329 s1 = Sphere_segment<R>(i1,target(),sphere_circle()); 00330 else CGAL_error_msg("no intersection."); 00331 return 1; 00332 } 00333 else if ( or1 == CGAL::ON_ORIENTED_BOUNDARY && 00334 or2 == CGAL::ON_ORIENTED_BOUNDARY ) { 00335 // if both ends of $s$ are part of $h$ then $s$ is a halfcircle or 00336 // $s$ is fully part of $h$. In this case we have to check if the 00337 // halfcircle is not part of $h^-$. This can be formulated by an 00338 // orientation test of the point $p$ at the tip of the normal of 00339 // |s.sphere_circle()| with respect to the plane through the 00340 // endpoints of $s$ and the tip of the normal of $h$. 00341 CGAL_NEF_TRACEN(" both in plane"); 00342 if ( source() != target().antipode() ) { 00343 s1 = *this; return 1; 00344 } 00345 // now this is a halfcircle 00346 register bool halfcircle_notin_hminus = 00347 (CGAL::orientation(source(),target(), 00348 CGAL::ORIGIN + c.orthogonal_vector(), 00349 CGAL::ORIGIN + sphere_circle().orthogonal_vector()) 00350 != CGAL::POSITIVE); 00351 CGAL_NEF_TRACE(" ");CGAL_NEF_TRACEV(halfcircle_notin_hminus); 00352 if ( halfcircle_notin_hminus ) { s1 = *this; return 1; } 00353 else { 00354 s1 = Sphere_segment(source(),source(),sphere_circle()); 00355 s2 = Sphere_segment(target(),target(),sphere_circle()); 00356 return 2; 00357 } 00358 } 00359 else if ( or1 != CGAL::ON_NEGATIVE_SIDE && 00360 or2 != CGAL::ON_NEGATIVE_SIDE ) { 00361 // this case covers the endpoints of $s$ as part of the closed 00362 // oriented halfspace $h^{0+}$. At least one is part of 00363 // $h^{+}$. If $s$ is not long then the segment must be fully part 00364 // of $h^{0+}$. Otherwise if $s$ is long, then we at both ends 00365 // there are subsegments as part of $h^{0+}$ (one might be 00366 // degenerate). 00367 if ( is_long() ) { 00368 Sphere_point<R> i1 = CGAL::intersection(this->ptr()->c_,c); 00369 Sphere_point<R> i2 = i1.antipode(); 00370 Sphere_segment<R> so(i1,i2,sphere_circle()); 00371 if ( so.has_on(source()) && so.has_on(target()) ) 00372 std::swap(i1,i2); 00373 // now source(),i1,i2,target() are circularly ordered 00374 s1 = Sphere_segment(source(),i1,sphere_circle()); 00375 s2 = Sphere_segment(i2,target(),sphere_circle()); 00376 CGAL_NEF_TRACEN(" both >= plane, long "<<s1<<s2); 00377 return 2; 00378 } // now short: 00379 CGAL_NEF_TRACEN(" both >= plane, short "); 00380 s1=*this; return 1; 00381 } 00382 else if ( or1 != CGAL::ON_POSITIVE_SIDE && 00383 or2 != CGAL::ON_POSITIVE_SIDE ) { 00384 // either both endpoints of $s$ are in $h^-$ or one is in $h^-$ 00385 // and one on $h^0$. 00386 if ( is_long() ) { 00387 Sphere_point<R> i1 = CGAL::intersection(this->ptr()->c_,c); 00388 Sphere_point<R> i2 = i1.antipode(); 00389 Sphere_segment<R> so(i1,i2,sphere_circle()); 00390 CGAL_NEF_TRACEN(" both <= plane, long"<<so); 00391 if ( so.has_on(source()) && so.has_on(target()) ) 00392 { so = so.complement(); } 00393 CGAL_NEF_TRACEN(" both <= plane, long"<<so); 00394 s1 = so; return 1; 00395 } // now short 00396 CGAL_NEF_TRACEN(" both <= plane, short"); 00397 if ( or1 == CGAL::ON_ORIENTED_BOUNDARY ) 00398 { s1 = Sphere_segment<R>(source(),source(),sphere_circle()); return 1; } 00399 if ( or2 == CGAL::ON_ORIENTED_BOUNDARY ) 00400 { s1 = Sphere_segment<R>(target(),target(),sphere_circle()); return 1; } 00401 return 0; 00402 } 00403 00404 CGAL_error_msg("Oops, forgot some case."); 00405 return -1; 00406 } 00407 00408 CGAL_END_NAMESPACE 00409 00410 #endif //CGAL_SPHERE_PREDICATES_H