IMP  2.0.0
The Integrative Modeling Platform
SphereD.h
Go to the documentation of this file.
1 /**
2  * \file IMP/algebra/SphereD.h \brief Simple 3D sphere class.
3  *
4  * Copyright 2007-2013 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPALGEBRA_SPHERE_D_H
9 #define IMPALGEBRA_SPHERE_D_H
10 
11 #include "algebra_macros.h"
12 #include "constants.h"
13 #include "BoundingBoxD.h"
14 #include "VectorD.h"
15 #include "utility.h"
16 #include "GeometricPrimitiveD.h"
17 #include <cmath>
18 
19 IMPALGEBRA_BEGIN_NAMESPACE
20 
21 /** Represent a sphere in D-dimensions.
22  \geometry
23  */
24 template <int D>
25 class SphereD: public GeometricPrimitiveD<D> {
26 public:
27  SphereD(){
28 #if IMP_HAS_CHECKS >= IMP_USAGE
29  radius_= std::numeric_limits<double>::quiet_NaN();
30 #endif
31  }
32  SphereD(const VectorD<D>& center,double radius):center_(center),
33  radius_(radius){
34  IMP_USAGE_CHECK(radius>=0, "Radius can't be negative");
35  }
36  double get_radius() const {
37  IMP_USAGE_CHECK(!base::isnan(radius_),
38  "Attempt to use uninitialized sphere.");
39  return radius_;
40  }
41  const VectorD<D> &get_center() const {return center_;}
42  //! Return true if this sphere contains the other one
43  bool get_contains(const SphereD<D> &o) const {
44  double d= (get_center()-o.get_center()).get_magnitude();
45  return (d+ o.get_radius() < get_radius());
46  }
47 
48  //! Return true if the point is in or on the surface of the sphere
49  /**
50  */
51  bool get_contains(const VectorD<D> &p) const {
52  return ((p-center_).get_squared_magnitude() <= get_squared(radius_));
53  }
55  out << "(" << spaces_io(center_) << ": " << get_radius()
56  << ")";
57  });
58 #ifndef IMP_DOXYGEN
59 #ifndef SWIG
60  VectorD<D> &_access_center() {
61  return center_;
62  }
63  void _set_radius(double d) {
64  radius_=d;
65  }
66  double &operator[](unsigned int i) {
67  IMP_USAGE_CHECK(i<D+1, "Out of range");
68  if (i <D) {
69  return center_[i];
70  } else {
71  return radius_;
72  }
73  }
74  double operator[](unsigned int i) const {
75  IMP_USAGE_CHECK(i<D+1, "Out of range");
76  if (i <D) {
77  return center_[i];
78  } else {
79  return radius_;
80  }
81  }
82 #endif
83 #endif
84  unsigned int get_dimension() const {
85  return center_.get_dimension();
86  }
87 private:
88  VectorD<D> center_;
89  double radius_;
90 };
91 
92 
93 IMP_VOLUME_GEOMETRY_METHODS_D(Sphere, sphere,
94  {
95  return PI * 4.0 * get_squared(g.get_radius());
96  },
97  {
98  return PI * (4.0 / 3.0)
99  * std::pow(g.get_radius(), 3.0);
100  },
101  return BoundingBoxD<D>(g.get_center())
102  +g.get_radius();
103  );
104 
105 template <unsigned int D>
106 inline SphereD<D> get_unit_sphere_d() {
107  return SphereD<D>(get_zero_vector_d<D>(), 1.0);
108 }
109 
110 inline SphereD<-1> get_unit_sphere_kd(unsigned int d) {
111  return SphereD<-1>(get_zero_vector_kd(d), 1.0);
112 }
113 
114 //! Return the distance between the two spheres if they are disjoint
115 /** If they intersect, the distances are not meaningful.
116  \relatesalso SphereD
117 */
118 template <int D>
119 inline double get_distance(const SphereD<D>& a, const SphereD<D> &b) {
120  double d= (a.get_center()-b.get_center()).get_magnitude();
121  return d - a.get_radius() - b.get_radius();
122 }
123 
124 //! Return the power distance between the two spheres
125 /** The power distance is the square of the distance between the centers
126  minus the sum of the square of the radii.
127  \relatesalso SphereD
128 */
129 template <int D>
130 inline double get_power_distance(const SphereD<D>& a, const SphereD<D> &b) {
131  double d= (a.get_center()-b.get_center()).get_squared_magnitude();
132  return d - square(a.get_radius()) - square(b.get_radius());
133 }
134 
135 
136 //! Return true if the two balls bounded by the two spheres interesect
137 /** \relatesalso SphereD
138  */
139 template <int D>
140 inline bool get_interiors_intersect(const SphereD<D> &a, const SphereD<D> &b) {
141  double sr= a.get_radius() + b.get_radius();
142  for (unsigned int i=0; i< 3; ++i) {
143  double delta=std::abs(a.get_center()[i]- b.get_center()[i]);
144  if (delta >= sr) return false;
145  }
146  return get_squared_distance(a.get_center(), b.get_center())
147  < get_squared(sr);
148 }
149 
150 #if !defined(SWIG) && !defined(IMP_DOXYGEN)
151 
152 namespace internal {
153  template <int D>
154  struct SphereSpacesIO
155  {
156  const SphereD<D> &v_;
157  SphereSpacesIO(const SphereD<D> &v): v_(v){}
158  };
159  template <int D>
160  inline std::ostream &operator<<(std::ostream &out, const SphereSpacesIO<D> &s)
161  {
162  for (unsigned int i=0; i< s.v_.get_center().get_dimension(); ++i) {
163  out << s.v_.get_center()[i] << " ";
164  }
165  out << s.v_.get_radius();
166  return out;
167  }
168 }
169 
170 //! Use this before outputing to a stream with spaces delimiting
171 /** std::cout << spaces_io(s);
172  produces "1.0 2.0 3.0 4.0" where the radius is 4.0
173  \relatesalso SphereD
174  */
175 template <int D>
176 inline internal::SphereSpacesIO<D> spaces_io(const SphereD<D> &v) {
177  return internal::SphereSpacesIO<D>(v);
178 }
179 #endif
180 
181 #ifdef IMP_DOXYGEN
182 //! Compute the bounding box of any geometric object
183 template <class Geometry>
184 BoundingBoxD<3> get_bounding_box(const Geometry &);
185 //! Compute the surface area of any volumetric object
186 template <class Geometry>
187 double get_surface_area(const Geometry &);
188 //! Compute the volume of any volumetric object
189 template <class Geometry>
190 double get_volume(const Geometry &);
191 //! Compute the area of any surface object
192 template <class Geometry>
193 double get_area(const Geometry &);
194 
195 #endif
196 template <int D>
197 VectorD<D> get_vector_d_geometry(const SphereD<D> &s) {
198  return s.get_center();
199 }
200 
201 IMPALGEBRA_END_NAMESPACE
202 
203 #endif /* IMPALGEBRA_SPHERE_D_H */