BWAPI
SPAR/AIModule/BWTA/vendors/CGAL/CGAL/Nef_S2/sphere_predicates.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines