dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/Nef_S2/Sphere_segment.h

398 lines
13 KiB
C
Raw Normal View History

// Copyright (c) 1997-2002 Max-Planck-Institute Saarbruecken (Germany).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Michael Seel <seel@mpi-sb.mpg.de>
#ifndef CGAL_SPHERE_SEGMENT_H
#define CGAL_SPHERE_SEGMENT_H
#include <CGAL/license/Nef_S2.h>
#include <CGAL/basic.h>
#include <CGAL/Handle_for.h>
#include <vector>
namespace CGAL {
template <class R_> class Sphere_segment_rep
{
typedef typename R_::Point_3 Point_3;
typedef typename R_::Plane_3 Plane_3;
typedef Sphere_point<R_> Point;
typedef Sphere_circle<R_> Circle;
typedef Sphere_segment_rep<R_> Rep;
friend class Sphere_segment<R_>;
public:
Sphere_segment_rep() { ps_ = pt_ = Point(); c_ = Circle(); }
Sphere_segment_rep(const Point& p1, const Point& p2,
bool shorter_arc=true) :
ps_(p1), pt_(p2), c_(Plane_3(p1,p2,Point_3(0,0,0)))
{ // warning stays as reminder that one gets an arbitrary plane equation
// in this degenerate case
CGAL_warning(p1 != p2.antipode());
CGAL_assertion(p1 != p2.antipode());
if ( p1 == p2 ) {
Plane_3 h(Point_3(0,0,0),(p1-CGAL::ORIGIN));
c_ = Sphere_circle<R_>(Plane_3(Point_3(0,0,0),h.base1()));
}
if (!shorter_arc) c_ = c_.opposite();
CGAL_exactness_assertion(c_.has_on(p1) && c_.has_on(p2));
}
Sphere_segment_rep(const Point& p1, const Point& p2, const Circle& c) :
ps_(p1), pt_(p2), c_(c)
{ CGAL_assertion(c.has_on(p1)&&c.has_on(p2)); }
Sphere_segment_rep(const Circle& c1,
const Circle& c2) : c_(c1)
{ CGAL_assertion(!equal_as_sets(c1,c2));
ps_ = intersection(c1,c2);
pt_ = ps_.antipode();
if ( R_::orientation(Point_3(0,0,0),ps_,pt_,
CGAL::ORIGIN + c_.orthogonal_vector()) !=
CGAL::POSITIVE ) std::swap(ps_,pt_);
}
Sphere_segment_rep(const Rep& r) :
ps_(r.ps_), pt_(r.pt_), c_(r.c_) {}
Rep& operator=(const Rep& r)
{ ps_=r.ps_; pt_=r.pt_; c_=r.c_; return *this; }
protected:
Sphere_point<R_> ps_,pt_;
Sphere_circle<R_> c_;
};
/*{\Moptions print_title=yes }*/
/*{\Manpage{Sphere_segment}{R}{Segments on the unit sphere}{s}}*/
template <class R_>
class Sphere_segment :
public Handle_for< Sphere_segment_rep<R_> > {
/*{\Mdefinition An object |\Mvar| of type |\Mname| is a segment in the
surface of a unit sphere that is part of a great circle trough the
origin. Sphere segments are represented by two sphere points $p$ and
$q$ plus an oriented plane $h$ that contains $p$ and $q$. The plane
determines the sphere segment. Let $c$ be the circle in the
intersection of $h$ and $S_2$. Then $s$ is that part of $c$ that is
swept, when we rotate $p$ into $q$ in counterclockwise rotation around
the normal vector of $h$ as seen from the positive halfspace.}*/
public:
/*{\Mtypes 6}*/
typedef R_ R;
/*{\Mtypemember representation class.}*/
typedef typename R_::RT RT;
/*{\Mtypemember ring number type.}*/
typedef Sphere_segment_rep<R_> Rep;
typedef Handle_for<Rep> Base;
typedef typename R_::Point_3 Point_3;
typedef typename R_::Vector_3 Vector_3;
typedef typename R_::Plane_3 Plane_3;
typedef typename R_::Line_3 Line_3;
typedef Sphere_segment<R_> Self;
/*{\Mcreation 4}*/
Sphere_segment() : Base() {}
Sphere_segment(const Sphere_point<R>& p1, const Sphere_point<R>& p2,
bool shorter_arc=true) : Base(Rep(p1,p2,shorter_arc)) {}
/*{\Mcreate creates a spherical segment spanning the shorter arc
from |p1| to |p2| if |shorter_arc == true|. Otherwise the longer
arc is created. \precond |p1 != p2| and |p1 != p2.antipode()|.}*/
Sphere_segment(const Sphere_point<R>& p1, const Sphere_point<R>& p2,
const Sphere_circle<R>& c) : Base(Rep(p1,p2,c)) {}
/*{\Mcreate creates a spherical segment spanning the arc
from |p1| to |p2| as part of the oriented circle |c|
(|p1 == p2| or |p1 == p2.antipode()| are possible.)
\precond |p1| and |p2| are contained in |c|.}*/
Sphere_segment(const Sphere_circle<R>& c1,
const Sphere_circle<R>& c2) : Base(Rep(c1,c2)) {}
/*{\Mcreate creates the spherical segment as part of |c1|
that is part of the halfsphere left of the oriented circle |c2|.
\precond |c1 != c2| as unoriented circles.}*/
Sphere_segment(const Self& s) : Base(s) {}
/*{\Moperations 4 2}*/
const Sphere_point<R>& source() const { return this->ptr()->ps_; }
/*{\Mop the source point of |\Mvar|.}*/
const Sphere_point<R>& target() const { return this->ptr()->pt_; }
/*{\Mop the target point of |\Mvar|.}*/
const Sphere_circle<R>& sphere_circle() const { return this->ptr()->c_; }
/*{\Mop the great circle supporting |\Mvar|.}*/
Sphere_segment<R> opposite() const
/*{\Mop returns the sperical segment oriented from |target()|
to |source()| with the same point set as |\Mvar|. }*/
{ return Sphere_segment<R>(
target(),source(),sphere_circle().opposite()); }
Sphere_segment<R> complement() const
/*{\Mop returns the sperical segment oriented from |target()|
to |source()| with the point set completing |\Mvar| to a
full circle. }*/
{ return Sphere_segment<R>(target(),source(),sphere_circle()); }
int intersection(const Sphere_circle<R>& c,
std::vector<Sphere_segment<R> >& s) const;
int intersection(const Sphere_circle<R>& c,
Sphere_segment<R>& s1, Sphere_segment<R>& s2) const;
/*{\Mop returns the number of non-trivial connected components
of the intersection of |\Mvar| and the closed halfsphere left of
|c|.}*/
Sphere_point<R> intersection(const Sphere_segment<R>& so) const;
/*{\Mop returns the point of intersection of |\Mvar| and
|so|. \precond |\Mvar| and |so| do intersect.}*/
void split_halfcircle(Sphere_segment<R>& s1,
Sphere_segment<R>& s2) const
/*{\Mop splits a halfcircle into two equally sized segments.
\precond |\Mvar| is a halfcircle.}*/
{ CGAL_assertion( is_halfcircle() );
Plane_3 h(Point_3(0,0,0),(target()-CGAL::ORIGIN));
Sphere_point<R> p =
CGAL::intersection(sphere_circle(),Sphere_circle<R>(h));
if ( !has_on(p) ) p = p.antipode();
s1 = Sphere_segment<R>(this->ptr()->ps_,p,this->ptr()->c_);
s2 = Sphere_segment<R>(p,this->ptr()->pt_,this->ptr()->c_);
}
bool is_short() const
/*{\Mop a segment is short iff it is shorter than a halfcircle.}*/
{
return R().orientation_3_object()(Point_3(0,0,0),
Point_3(source()),
Point_3(target()),
CGAL::ORIGIN +
this->ptr()->c_.orthogonal_vector())
== CGAL::POSITIVE; }
bool is_long() const
/*{\Mop a segment is long iff it is longer than a halfcircle.}*/
{ return R().orientation_3_object()(Point_3(0,0,0),
Point_3(source()),
Point_3(target()),
CGAL::ORIGIN + this->ptr()->c_.orthogonal_vector())
== CGAL::NEGATIVE; }
bool is_degenerate() const { return source() == target(); }
/*{\Mop return true iff |\Mvar| is degenerate.}*/
bool is_halfcircle() const { return source().antipode() == target(); }
/*{\Mop return true iff |\Mvar| is a halfcircle.}*/
bool has_on(const Sphere_point<R>& p) const;
/*{\Mop return true iff |\Mvar| contains |p|.}*/
bool has_on_after_intersection(const Sphere_point<R>& p) const;
bool has_in_relative_interior(const Sphere_point<R>& p) const;
/*{\Mop return true iff |\Mvar| contains |p| in
its relative interior.}*/
bool operator==(const Sphere_segment<R>& so) const
{ return source() == so.source() && target() == so.target() &&
(source() == target() ||
sphere_circle() == so.sphere_circle()); }
bool operator!=(const Sphere_segment<R>& so) const
{ return !operator==(so); }
};
template <typename R>
bool do_intersect_internally(const Sphere_segment<R>& s1,
const Sphere_segment<R>& s2,
Sphere_point<R>& p);
/*{\Mfunc return true iff |s1| and |s2| intersect internally
(non-degenerately). If |true| the parameter |p| returns the point of
intersection.}*/
template <typename R>
std::ostream& operator<<(std::ostream& os,
const CGAL::Sphere_segment<R>& s)
{ os << s.source()<<" "<<s.target()<<" "<<
s.sphere_circle().plane()<<" "; return os; }
template <typename R>
std::istream& operator>>(std::istream& is,
CGAL::Sphere_segment<R>& s)
{ CGAL::Sphere_point<R> p1,p2;
CGAL::Sphere_circle<R> c;
if ( !(is >> p1 >> p2 >> c) ) return is;
s = CGAL::Sphere_segment<R>(p1,p2,c);
return is; }
template <typename R>
std::pair< Sphere_segment<R>,Sphere_segment<R> >
Sphere_circle<R>::split_at(const Sphere_point<R>& p) const
{ CGAL_assertion(has_on(p));
Sphere_point<R> q(p.antipode());
return Sphere_segment_pair(
Sphere_segment<R>(p,q,*this),
Sphere_segment<R>(p,q,this->opposite()));
}
template <typename R>
std::pair< Sphere_segment<R>,Sphere_segment<R> >
Sphere_circle<R>::split_at_xy_plane() const
{ Self xycircle(0,0,1), yzcircle(1,0,0);
if ( !equal_as_sets(xycircle,*this) )
return split_at(intersection(*this,xycircle));
else
return split_at(intersection(*this,yzcircle));
}
/* Contains maps to two orientation checks with the wedge
spanned by the source and the target with planes orthogonal
to the supporting plane of $p$ and $q$. The logic depends on
the segments length: long or short. */
template <typename R>
bool Sphere_segment<R>::
has_on(const CGAL::Sphere_point<R>& p) const
{ if ( !sphere_circle().has_on(p) ) return false;
if ( !is_long() ) {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) !=
CGAL::NEGATIVE &&
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) !=
CGAL::NEGATIVE;
} else {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) !=
CGAL::NEGATIVE ||
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) !=
CGAL::NEGATIVE;
}
}
template <typename R>
bool Sphere_segment<R>::
has_on_after_intersection(const CGAL::Sphere_point<R>& p) const {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) !=
CGAL::NEGATIVE &&
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) !=
CGAL::NEGATIVE;
}
template <typename R>
bool Sphere_segment<R>::
has_in_relative_interior(const CGAL::Sphere_point<R>& p) const
{ if ( !sphere_circle().has_on(p) ) return false;
if ( !is_long() ) {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) == CGAL::POSITIVE &&
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) ==
CGAL::POSITIVE;
} else {
return orientation(Point_3(0,0,0),
CGAL::ORIGIN + sphere_circle().orthogonal_vector(),
source(),p) == CGAL::POSITIVE ||
orientation(Point_3(0,0,0),target(),
CGAL::ORIGIN +
sphere_circle().orthogonal_vector(),p) ==
CGAL::POSITIVE;
}
}
/* Intersection of two sphere segments. It does not work if the two
involved planes are equal as sets. */
template <typename R>
Sphere_point<R> Sphere_segment<R>::
intersection(const Sphere_segment<R>& s) const
{
CGAL_assertion(!equal_as_sets(sphere_circle(),s.sphere_circle()));
Sphere_point<R> res =
CGAL::intersection(sphere_circle(),s.sphere_circle());
if ( has_on(res) && s.has_on(res) ) return res;
return res.antipode();
}
template <typename R>
bool do_intersect_internally(const Sphere_segment<R>& s1,
const Sphere_segment<R>& s2,
Sphere_point<R>& p)
{
if ( equal_as_sets(s1.sphere_circle(),s2.sphere_circle()) )
return false;
p = CGAL::intersection(s1.sphere_circle(),s2.sphere_circle());
if ( s1.has_in_relative_interior(p) &&
s2.has_in_relative_interior(p) ) return true;
p = p.antipode();
if ( s1.has_in_relative_interior(p) &&
s2.has_in_relative_interior(p) ) return true;
return false;
}
template <typename R>
bool do_intersect_internally(const Sphere_circle<R>& c1,
const Sphere_segment<R>& s2,
Sphere_point<R>& p)
{
if ( equal_as_sets(c1,s2.sphere_circle()) )
return false;
p = CGAL::intersection(c1,s2.sphere_circle());
if ( s2.has_in_relative_interior(p) ) return true;
p = p.antipode();
if ( s2.has_in_relative_interior(p) ) return true;
return false;
}
} //namespace CGAL
#endif //CGAL_SPHERE_SEGMENT_H