]> git.mxchange.org Git - simgear.git/blob - simgear/math/SGSphere.hxx
Allow geocentric distance computations to return radians.
[simgear.git] / simgear / math / SGSphere.hxx
1 // Copyright (C) 2006  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #ifndef SGSphere_H
19 #define SGSphere_H
20
21 template<typename T>
22 class SGSphere {
23 public:
24   SGSphere() :
25     _radius(-1)
26   { }
27   SGSphere(const SGVec3<T>& center, const T& radius) :
28     _center(center),
29     _radius(radius)
30   { }
31   template<typename S>
32   explicit SGSphere(const SGSphere<S>& sphere) :
33     _center(sphere.getCenter()),
34     _radius(sphere.getRadius())
35   { }
36
37   const SGVec3<T>& getCenter() const
38   { return _center; }
39   void setCenter(const SGVec3<T>& center)
40   { _center = center; }
41
42   const T& getRadius() const
43   { return _radius; }
44   void setRadius(const T& radius)
45   { _radius = radius; }
46   T getRadius2() const
47   { return _radius*_radius; }
48
49   bool empty() const
50   { return !valid(); }
51
52   bool valid() const
53   { return 0 <= _radius; }
54
55   void clear()
56   { _radius = -1; }
57
58   void expandBy(const SGVec3<T>& v)
59   {
60     if (empty()) {
61       _center = v;
62       _radius = 0;
63       return;
64     }
65
66     T dist2 = distSqr(_center, v);
67     if (dist2 <= getRadius2())
68       return;
69
70     T dist = sqrt(dist2);
71     T newRadius = T(0.5)*(_radius + dist);
72     _center += ((newRadius - _radius)/dist)*(v - _center);
73     _radius = newRadius;
74   }
75
76   void expandBy(const SGSphere<T>& s)
77   {
78     if (s.empty())
79       return;
80
81     if (empty()) {
82       _center = s.getCenter();
83       _radius = s.getRadius();
84       return;
85     }
86
87     T dist = length(_center - s.getCenter());
88     if (dist <= SGLimits<T>::min()) {
89       _radius = SGMisc<T>::max(_radius, s._radius);
90       return;
91     }
92
93     // already included
94     if (dist + s.getRadius() <= _radius)
95       return;
96
97     // new one includes all
98     if (dist + _radius <= s.getRadius()) {
99       _center = s.getCenter();
100       _radius = s.getRadius();
101       return;
102     }
103
104     T newRadius = T(0.5)*(_radius + dist + s.getRadius());
105     T ratio = (newRadius - _radius) / dist;
106     _radius = newRadius;
107
108     _center[0] += ratio*(s._center[0] - _center[0]);
109     _center[1] += ratio*(s._center[1] - _center[1]);
110     _center[2] += ratio*(s._center[2] - _center[2]);
111   }
112
113   void expandBy(const SGBox<T>& box)
114   {
115     if (box.empty())
116       return;
117
118     if (empty()) {
119       _center = box.getCenter();
120       _radius = T(0.5)*length(box.getSize());
121       return;
122     }
123
124     SGVec3<T> boxCenter = box.getCenter();
125     SGVec3<T> corner;
126     for (unsigned i = 0; i < 3; ++i) {
127       if (_center[i] < boxCenter[i])
128         corner[i] = box.getMax()[i];
129       else
130         corner[i] = box.getMin()[i];
131     }
132     expandBy(corner);
133   }
134
135 private:
136   SGVec3<T> _center;
137   T _radius;
138 };
139
140 /// Output to an ostream
141 template<typename char_type, typename traits_type, typename T>
142 inline
143 std::basic_ostream<char_type, traits_type>&
144 operator<<(std::basic_ostream<char_type, traits_type>& s,
145            const SGSphere<T>& sphere)
146 {
147   return s << "center = " << sphere.getCenter()
148            << ", radius = " << sphere.getRadius();
149 }
150
151 #endif