1 // This is bbas/vsph/vsph_sph_box_2d.cxx
2 #include "vsph_sph_box_2d.h"
3 #include "vsph_utils.h"
4 #include "vsph_defs.h"
5 #include "vsph_unit_sphere.h"
6 #include <bvrml/bvrml_write.h>
7 #include <cassert>
8 #ifdef _MSC_VER
9 #  include "vcl_msvc_warnings.h"
10 #endif
11 #include "vgl/vgl_vector_3d.h"
12 
pye() const13 double vsph_sph_box_2d::pye() const
14 {
15   if (in_radians_) return vnl_math::pi;
16   return 180.0;
17 }
18 
reduce_phi(double phi) const19 double vsph_sph_box_2d::reduce_phi(double phi) const
20 {
21   double ph = phi;
22   if (ph>pye()) ph -= vnl_math::twopi;
23   if (ph<-pye()) ph +=  vnl_math::twopi;
24   return ph;
25 }
26 
b_ccw_a()27 void vsph_sph_box_2d::b_ccw_a()
28 {
29   if (!defined()) return;
30   double dif = vsph_utils::azimuth_diff(a_phi_, b_phi_, in_radians_);
31   if (dif<0) {
32     double a_ph = a_phi_;
33     a_phi_ = b_phi_;
34     b_phi_ = a_ph;
35   }
36 }
37 
set_comparisons()38 void vsph_sph_box_2d::set_comparisons()
39 {
40   a_ge_zero_ = a_phi_ >= 0.0;
41   b_le_zero_ = b_phi_ <= 0.0;
42   b_lt_zero_ = b_phi_ < 0.0;
43   c_gt_a_ = c_phi_> a_phi_;
44   c_lt_b_ = c_phi_ < b_phi_;
45   c_le_pi_ = c_phi_<=pye();
46   c_ge_mpi_ = c_phi_>=-pye();
47   c_ge_zero_ = c_phi_>=0.0;
48 }
49 
phi_bounds(double & phi_start,double & phi_end) const50 void vsph_sph_box_2d::phi_bounds(double& phi_start, double& phi_end) const
51 {
52   // assume that b_phi_ is ccw of a_phi_
53   double ph_start = a_phi_, ph_end = b_phi_;
54   phi_start = ph_start; phi_end = ph_end;
55   // start and end the same sign
56   if ((!a_ge_zero_ && b_lt_zero_)||(a_ge_zero_ && !b_lt_zero_)) {
57     double mid = 0.5*(ph_start + ph_end);
58     if (!(this->in_interval(mid, in_radians_))) {
59       phi_start = ph_end;
60       phi_end = ph_start;
61     }
62     return;
63   }
64   // signs are different
65   if (!a_ge_zero_&& !b_lt_zero_) {
66     if (this->in_interval(pye(), in_radians_)) {
67       phi_start = ph_end;
68       phi_end = ph_start;
69     }
70     return;
71   }
72   if (a_ge_zero_ && b_lt_zero_) {
73     if (!(this->in_interval(pye(), in_radians_))) {
74       phi_start = ph_end;
75       phi_end = ph_start;
76     }
77     return;
78   }
79   assert(false);
80   std::cout<< "IMPOSSIBLE CONDITION in phi_bounds(..)\n";
81 }
82 
vsph_sph_box_2d()83 vsph_sph_box_2d::vsph_sph_box_2d(): in_radians_(true)
84 {
85   min_th_ = max_th_= 1000.0; //empty
86   a_phi_ = b_phi_ = c_phi_ = 1000.0;
87 }
88 
vsph_sph_box_2d(bool in_radians)89 vsph_sph_box_2d::vsph_sph_box_2d(bool in_radians): in_radians_(in_radians)
90 {
91   min_th_ = max_th_= 1000.0; //empty
92   a_phi_ = b_phi_ = c_phi_ = 1000.0;
93   min_phi_ = max_phi_ = 1000.0;
94 }
95 
vsph_sph_box_2d(const vsph_sph_box_2d & sbox)96 vsph_sph_box_2d::vsph_sph_box_2d(const vsph_sph_box_2d& sbox)
97 {
98   in_radians_ = sbox.in_radians();
99   a_phi_ = sbox.a_phi(in_radians_);
100   b_phi_ = sbox.b_phi(in_radians_);
101   c_phi_ = sbox.c_phi(in_radians_);
102   min_th_ = sbox.min_theta(in_radians_);
103   max_th_ = sbox.max_theta(in_radians_);
104   min_phi_ = sbox.min_phi(in_radians_);
105   max_phi_ = sbox.max_phi(in_radians_);
106   this->set_comparisons();
107 }
108 
vsph_sph_box_2d(vsph_sph_point_2d const & pa,vsph_sph_point_2d const & pb,vsph_sph_point_2d const & pc)109 vsph_sph_box_2d::vsph_sph_box_2d(vsph_sph_point_2d const& pa,
110                                  vsph_sph_point_2d const& pb,
111                                  vsph_sph_point_2d const& pc)
112 {
113   min_th_ = max_th_= 1000.0; //empty
114   a_phi_ = b_phi_ = c_phi_ = 1000.0;
115   //assume all the points are in the same units
116   in_radians_ = pa.in_radians_;
117   double a_th = pa.theta_, b_th = pb.theta_, c_th = pc.theta_;
118   min_th_ = a_th;
119   max_th_ = b_th;
120   if (b_th < a_th) {
121     min_th_ = b_th;
122     max_th_ = a_th;
123   }
124   if (c_th<min_th_) min_th_ = c_th;
125   if (c_th>max_th_) max_th_ = c_th;
126   a_phi_ = pa.phi_;   b_phi_ = pb.phi_; c_phi_ = pc.phi_;
127   this->b_ccw_a();
128   this->set_comparisons();
129   this->phi_bounds(min_phi_, max_phi_);
130 }
131 
132 // want the phi value that is clockwise of phi_c in the box interval
min_phi(bool in_radians) const133 double vsph_sph_box_2d::min_phi(bool in_radians) const
134 {
135   if ((in_radians&&in_radians_)||(!in_radians&&!in_radians_))
136     return min_phi_;
137   else if (in_radians&&!in_radians_)
138     return min_phi_/vnl_math::deg_per_rad;
139   else
140     return min_phi_*vnl_math::deg_per_rad;
141 }
142 
min_theta(bool in_radians) const143 double vsph_sph_box_2d::min_theta(bool in_radians) const
144 {
145   if ((in_radians&&in_radians_)||(!in_radians&&!in_radians_))
146     return min_th_;
147   else if (in_radians&&!in_radians_)
148     return min_th_/vnl_math::deg_per_rad;
149   else
150     return min_th_*vnl_math::deg_per_rad;
151 }
152 
153 // want the phi value that is counter clockwise of phi_c in the box interval
max_phi(bool in_radians) const154 double vsph_sph_box_2d::max_phi(bool in_radians) const
155 {
156   if ((in_radians&&in_radians_)||(!in_radians&&!in_radians_))
157     return max_phi_;
158   else if (in_radians&&!in_radians_)
159     return max_phi_/vnl_math::deg_per_rad;
160   else
161     return max_phi_*vnl_math::deg_per_rad;
162 }
163 
max_theta(bool in_radians) const164 double vsph_sph_box_2d::max_theta(bool in_radians) const
165 {
166   if ((in_radians&&in_radians_)||(!in_radians&&!in_radians_))
167     return max_th_;
168   else if (in_radians&&!in_radians_)
169     return max_th_/vnl_math::deg_per_rad;
170   else
171     return max_th_*vnl_math::deg_per_rad;
172 }
173 
a_phi(bool in_radians) const174 double vsph_sph_box_2d::a_phi(bool in_radians) const
175 {
176   if ((in_radians&&in_radians_)||(!in_radians&&!in_radians_))
177     return a_phi_;
178   else if (in_radians&&!in_radians_)
179     return a_phi_/vnl_math::deg_per_rad;
180   else
181     return a_phi_*vnl_math::deg_per_rad;
182 }
183 
b_phi(bool in_radians) const184 double vsph_sph_box_2d::b_phi(bool in_radians) const
185 {
186   if ((in_radians&&in_radians_)||(!in_radians&&!in_radians_))
187     return b_phi_;
188   else if (in_radians&&!in_radians_)
189     return b_phi_/vnl_math::deg_per_rad;
190   else
191     return b_phi_*vnl_math::deg_per_rad;
192 }
193 
c_phi(bool in_radians) const194 double vsph_sph_box_2d::c_phi(bool in_radians) const
195 {
196   if ((in_radians&&in_radians_)||(!in_radians&&!in_radians_))
197     return c_phi_;
198   else if (in_radians&&!in_radians_)
199     return c_phi_/vnl_math::deg_per_rad;
200   else
201     return c_phi_*vnl_math::deg_per_rad;
202 }
203 
min_point(bool in_radians) const204 vsph_sph_point_2d vsph_sph_box_2d::min_point(bool in_radians) const
205 {
206   double theta_min = min_th_;
207   if (in_radians&&!in_radians_)
208     theta_min /= vnl_math::deg_per_rad;
209   if (!in_radians&&in_radians_)
210     theta_min *= vnl_math::deg_per_rad;
211   double ph_min = this->min_phi(in_radians);
212   return vsph_sph_point_2d(theta_min, ph_min, in_radians);
213 }
214 
215 
max_point(bool in_radians) const216 vsph_sph_point_2d vsph_sph_box_2d::max_point(bool in_radians) const
217 {
218   double theta_max = max_th_;
219   if (in_radians&&!in_radians_)
220     theta_max /= vnl_math::deg_per_rad;
221   if (!in_radians&&in_radians_)
222     theta_max *= vnl_math::deg_per_rad;
223   double ph_max = this->max_phi(in_radians);
224   return vsph_sph_point_2d(theta_max, ph_max, in_radians);
225 }
226 
set(double min_theta,double max_theta,double a_phi,double b_phi,double c_phi,bool in_radians)227 void vsph_sph_box_2d::set(double min_theta, double max_theta,
228                           double a_phi, double b_phi,
229                           double c_phi, bool in_radians)
230 {
231   min_th_ = min_theta; max_th_ = max_theta;
232   a_phi_ = a_phi;   b_phi_ = b_phi;   c_phi_ = c_phi;
233   in_radians_ = in_radians;
234   this->b_ccw_a();
235   this->set_comparisons();
236   this->phi_bounds(min_phi_, max_phi_);
237 }
238 
operator =(const vsph_sph_box_2d & rhs)239 vsph_sph_box_2d& vsph_sph_box_2d::operator= (const vsph_sph_box_2d & rhs)
240 {
241   if (this != &rhs) {
242     bool in_radians = rhs.in_radians();
243     this->set(rhs.min_theta(in_radians), rhs.max_theta(in_radians),
244               rhs.a_phi(in_radians), rhs.b_phi(in_radians),
245               rhs.c_phi(in_radians), in_radians);
246   }
247   return *this;
248 }
249 
is_empty() const250 bool vsph_sph_box_2d::is_empty() const
251 {
252   return min_th_ == 1000.0;
253 }
254 
defined() const255 bool vsph_sph_box_2d::defined() const
256 {
257   return c_phi_ != 1000.0;
258 }
259 
update_theta(double th)260 void  vsph_sph_box_2d::update_theta(double th)
261 {
262   if (th< min_th_)  min_th_ = th;
263   if (th> max_th_)   max_th_ = th;
264 }
265 
extend_interval(double ph)266 bool vsph_sph_box_2d::extend_interval(double ph)
267 {
268   if (!defined()) return false;//can't extend
269 
270   double dpa = vsph_utils::azimuth_diff(a_phi_, ph,  in_radians_);
271   double dpb = vsph_utils::azimuth_diff(b_phi_, ph,  in_radians_);
272   dpa = std::fabs(dpa); dpb = std::fabs(dpb);
273   if (dpa <= dpb)
274     a_phi_ = ph;
275   else
276     b_phi_ = ph;
277 
278   return true;
279 }
280 
add(double theta,double phi,bool in_radians)281 void vsph_sph_box_2d::add( double theta, double phi, bool in_radians)
282 {
283   double ph = phi, th = theta;
284   // convert input angles to box angle units
285   if (in_radians&&!in_radians_) {
286     ph*=vnl_math::deg_per_rad; th*=vnl_math::deg_per_rad;
287   }
288   else if (!in_radians&&in_radians_) {
289     ph/=vnl_math::deg_per_rad; th/=vnl_math::deg_per_rad;
290   }   // the first point is being added
291   if (this->is_empty()) {
292     min_th_ = th;
293     a_phi_ = phi;
294     return;
295   }
296   if ( max_th_ == 1000.0) {//the 2nd point is being added
297     if (th<min_th_) {
298       max_th_ = min_th_;
299       min_th_ = th;
300     }
301     else {
302       max_th_ = th;
303     }
304     // case equal
305     if (vsph_utils::a_eq_b(ph, a_phi_)) {
306       b_phi_ = ph;
307       return;
308     }
309     // case unequal
310     if (vsph_utils::a_lt_b(ph, a_phi_)) {
311       b_phi_ = a_phi_;
312       a_phi_ = ph;
313       return;
314     }
315     b_phi_ = ph;
316     return;
317   }//end 2nd point added
318   if (!defined()) { // point c potentially added
319     this->update_theta(th);
320     // if point is equal to bounds then interval membership still undefined
321     if (vsph_utils::a_eq_b(ph, a_phi_)||vsph_utils::a_eq_b(ph, b_phi_))
322       return;
323     // ok to update with point c
324     c_phi_ = ph;
325     // all three points are defined so can set up the compact interval
326     // find the interpoint distances
327     double dab = std::fabs(vsph_utils::azimuth_diff(a_phi_, b_phi_, in_radians_));
328     double dac = std::fabs(vsph_utils::azimuth_diff(a_phi_, c_phi_, in_radians_));
329     double dbc = std::fabs(vsph_utils::azimuth_diff(b_phi_, c_phi_, in_radians_));
330     // assign the points so that a < c < b in the smaller interval
331     double ang_a = a_phi_, ang_b = b_phi_, ang_c = c_phi_;
332     if (dab>dac && dab>dbc) {
333       if (vsph_utils::a_lt_b(ang_a, ang_b, in_radians_)) {
334         a_phi_ = ang_a; b_phi_ = ang_b; c_phi_ = ang_c;
335       }
336       else {
337         b_phi_ = ang_a; a_phi_ = ang_b; c_phi_ = ang_c;
338       }
339     }
340     if (dac>dbc && dac>dab) {
341       if (vsph_utils::a_lt_b(ang_a, ang_c, in_radians_)) {
342         a_phi_ = ang_a; b_phi_ = ang_c; c_phi_ = ang_b;
343       }
344       else {
345         b_phi_ = ang_a; a_phi_ = ang_c; c_phi_ = ang_b;
346       }
347     }
348     if (dbc>dac && dbc>dab) {
349       if (vsph_utils::a_lt_b(ang_b, ang_c, in_radians_)) {
350         a_phi_ = ang_b; b_phi_ = ang_c; c_phi_ = ang_a;
351       }
352       else {
353         b_phi_ = ang_b; a_phi_ = ang_c; c_phi_ = ang_a;
354       }
355     }
356     this->b_ccw_a();
357     this->set_comparisons();
358     this->phi_bounds(min_phi_, max_phi_);
359     return;
360   }
361   // the interval is established so carry out normal updates
362   this->update_theta(th);
363   if (this->in_interval(ph, in_radians_)) return;
364   bool success = this->extend_interval(ph);
365   assert(success);
366   this->b_ccw_a();
367   this->set_comparisons();
368   this->phi_bounds(min_phi_, max_phi_);
369 }
370 
contains(vsph_sph_point_2d const & p) const371 bool vsph_sph_box_2d::contains(vsph_sph_point_2d const& p) const
372 {
373   return contains(p.theta_, p.phi_, p.in_radians_);
374 }
375 
in_interval(double phi,bool in_radians) const376 bool vsph_sph_box_2d::in_interval(double phi, bool in_radians) const
377 {
378   if (!defined()) return false;//inside an interval is undefined
379   double ph = phi;
380   // convert input angles to box angle units
381   if (in_radians&&!in_radians_) {
382     ph*=vnl_math::deg_per_rad;
383   }
384   else if (!in_radians&&in_radians_) {
385     ph/=vnl_math::deg_per_rad;
386   }
387   // small interval contains 180
388   if (a_ge_zero_&&b_le_zero_) {
389     // is the interval the small interval?
390     if (( c_gt_a_&& c_le_pi_) || (c_ge_mpi_ && c_lt_b_)) {
391       //yes
392       bool in = (ph>= a_phi_ && ph<=pye()) ||
393                 (ph >= -pye() && ph <= b_phi_);
394       return in;
395     }
396     // the interval is the long interval
397       bool in = (ph<= a_phi_ && ph>=0.0) ||
398                 (ph <= 0 && ph >= b_phi_);
399       return in;
400   }
401   // small interval doesn't contain 180
402   if (c_gt_a_ && c_lt_b_)  // small interval
403     return ph >= a_phi_ && ph <= b_phi_;
404   else //long interval
405     return (ph<=a_phi_ && ph>=-pye() ) || (ph<=pye()&& ph>=b_phi_);
406 }
407 
408 #if 0
409 bool vsph_sph_box_2d::in_interval(double phi, bool in_radians) const
410 {
411   if (!defined()) return false;//inside an interval is undefined
412   double ph = phi;
413   // convert input angles to box angle units
414   if (in_radians&&!in_radians_) {
415     ph*=vnl_math::deg_per_rad;
416   }
417   else if (!in_radians&&in_radians_) {
418     ph/=vnl_math::deg_per_rad;
419   }
420   // this difference is always less that 180.0
421   double dif = vsph_utils::azimuth_diff(a_phi_, b_phi_, in_radians_);
422   double start_ang = a_phi_, end_ang = b_phi_;
423   if (dif<0) {
424     start_ang = b_phi_;
425     end_ang = a_phi_;
426   }
427   // small interval contains 180
428   if (start_ang >0 && end_ang<0) {
429     // is the interval the short interval?
430     if ((c_phi_> start_ang && c_phi_<=pye()) ||
431         (c_phi_ >= -pye() && c_phi_ < end_ang)) {
432       //yes
433       bool in = (ph>= start_ang && ph<=pye()) ||
434                 (ph >= -pye() && ph <= end_ang);
435       return in;
436     }
437     // is the interval the long interval
438     if ((c_phi_< start_ang && c_phi_>=0.0) ||
439         (c_phi_ < 0 && c_phi_ > end_ang)) {
440       //yes
441       bool in = (ph<= start_ang && ph>=0.0) ||
442                 (ph <= 0 && ph >= end_ang);
443       return in;
444     }
445     // can't happen
446     assert(false);
447   }
448   // small interval doesn't contain 180
449   if (c_phi_ > start_ang && c_phi_ < end_ang)  // small interval
450     return ph >= start_ang && ph <= end_ang;
451   else //long interval
452     return (ph<=start_ang && ph>=-pye() ) ||
453       (ph<=pye()     && ph>=end_ang);
454 }
455 #endif
456 
operator ==(const vsph_sph_box_2d & other) const457 bool vsph_sph_box_2d::operator==(const vsph_sph_box_2d& other) const
458 {
459   if (this == &other) return true; //the same instance
460   // can't convert units and still be exactly equal
461   if (other.in_radians()!=in_radians_)
462     return false;
463   double min_th = other.min_theta(), max_th = other.max_theta();
464   if ((min_th != min_th_) || (max_th != max_th_))
465     return false;
466   double a = other.a_phi(), b = other.b_phi(), c = other.c_phi();
467   if (!(((a==a_phi_)&&(b==b_phi_))||((a==b_phi_)&&(b==a_phi_))))
468     return false;
469   if (c_phi_==c) return true;
470   // the c location can differ without altering the actual spherical interval.
471   if (!this->in_interval(c, in_radians_))
472     return false;
473   if (!other.in_interval(c_phi_, in_radians_))
474     return false;
475   return true;
476 }
477 
contains(double const & theta,double const & phi,bool in_radians) const478 bool vsph_sph_box_2d::contains(double const& theta, double const& phi,
479                                bool in_radians) const
480 {
481   double ph = phi, th = theta;
482   // convert input angles to box angle units
483   if (in_radians&&!in_radians_) {
484     ph*=vnl_math::deg_per_rad; th*=vnl_math::deg_per_rad;
485   }
486   else if (!in_radians&&in_radians_) {
487     ph/=vnl_math::deg_per_rad; th/=vnl_math::deg_per_rad;
488   }
489   // do the easy case first
490   double min_th = min_theta(in_radians_);
491   double max_th = max_theta(in_radians_);
492   if (th < min_th || th > max_th) return false;
493   // treatment of the +-180 cut and large vs. small arc defined by two points
494   return in_interval(ph, in_radians_);
495 }
496 
contains(vsph_sph_box_2d const & b) const497 bool vsph_sph_box_2d::contains(vsph_sph_box_2d const& b) const
498 {
499   double b_min_th = b.min_theta(in_radians_), b_max_th = b.max_theta(in_radians_);
500   bool in_theta = b_min_th >= min_th_ && b_max_th<=max_th_;
501   if (!in_theta) return false;
502   bool in_phi = in_interval(b.min_phi(in_radians_), in_radians_) &&
503     in_interval(b.max_phi(in_radians_), in_radians_) &&
504     in_interval(b.c_phi(in_radians_), in_radians_);
505   return in_phi;
506 }
507 
area() const508 double vsph_sph_box_2d::area() const
509 {
510   //everything in radians
511   double min_ph = min_phi(true), max_ph = max_phi(true);
512   double min_th = min_theta(true), max_th = max_theta(true);
513   double a = std::fabs(std::cos(min_th)-std::cos(max_th));
514   double ang1, ang2;
515   vsph_utils::half_angle(min_ph, max_ph, ang1, ang2, true);
516   double ha = ang2;
517   if (this->in_interval(ang1, true))
518     ha = ang1;
519   double dif = std::fabs(vsph_utils::azimuth_diff(min_ph, ha, true));
520   dif += std::fabs(vsph_utils::azimuth_diff(ha, max_ph, true));
521   return a*dif;
522 }
523 
center(bool in_radians) const524 vsph_sph_point_2d vsph_sph_box_2d::center(bool in_radians) const
525 {
526   double min_ph = min_phi(true), max_ph = max_phi(true);
527   double min_th = min_theta(true), max_th = max_theta(true);
528   double half_th = (min_th + max_th)/2.0;
529   double ang1, ang2;
530   vsph_utils::half_angle(min_ph, max_ph, ang1, ang2, true);
531   double ha = ang2;
532   if (this->in_interval(ang1, true))
533     ha = ang1;
534 
535   if (!in_radians) {
536     half_th *= vnl_math::deg_per_rad;
537     ha *= vnl_math::deg_per_rad;
538   }
539 
540   return vsph_sph_point_2d(half_th, ha, in_radians);
541 }
542 
transform(double t_theta,double t_phi,double scale,bool in_radians) const543 vsph_sph_box_2d vsph_sph_box_2d::transform(double t_theta,
544                                            double t_phi, double scale,
545                                            bool in_radians) const
546 {
547   //work in units of *this box
548   double d_th = t_theta, d_ph = t_phi;
549   if (this->in_radians_ && !in_radians) {
550     d_th /= vnl_math::deg_per_rad;
551     d_ph /= vnl_math::deg_per_rad;
552   }
553   if (!this->in_radians_ && in_radians) {
554     d_th *= vnl_math::deg_per_rad;
555     d_ph *= vnl_math::deg_per_rad;
556   }
557   //first scale *this box and then rotate
558   //scaling should occur around the box center
559   //angular spread of both theta and phi is multiplied by scale
560   vsph_sph_point_2d center = this->center(in_radians_);
561   double min_th = min_theta(in_radians_), max_th = max_theta(in_radians_);
562   double cth = center.theta_, scth = (cth-min_th)*scale;
563   min_th = cth-scth, max_th = cth + scth;
564   // now rotate theta
565   min_th += d_th, max_th += d_th;
566   // don't allow transformations on theta that move outside range
567   if (min_th<0.0) min_th = 0.0;
568   if (max_th>pye())max_th = pye();
569   // for phi it is possible to scale beyond 360 degrees. Don't allow this.
570   // stop at the full circle and put phi_c at half angle opposite the
571   // circle cut.
572   double c_ph = center.phi_;
573   double ph_start=min_phi_, ph_end = max_phi_;
574   double difs = std::fabs(vsph_utils::azimuth_diff(ph_start, c_ph, in_radians_));
575   double dife = std::fabs(vsph_utils::azimuth_diff(c_ph, ph_end, in_radians_));
576   double s = scale;
577   if (s*(difs+dife) > 2.0*pye()) {
578     ph_end = ph_start;
579   }
580   else {
581     //extend the start and end positions
582     difs *=s;
583     ph_start = c_ph -difs + d_ph;
584     ph_end = c_ph + difs + d_ph;
585     c_ph += d_ph;
586     ph_start = reduce_phi(ph_start);
587     ph_end = reduce_phi(ph_end);
588     c_ph = reduce_phi(c_ph);
589   }
590   vsph_sph_box_2d rbox;
591   rbox.set(min_th, max_th, ph_start, ph_end, c_ph, in_radians_);
592   return rbox;
593 }
594 
595 
transform(double t_theta,double t_phi,double scale,double theta_c,double phi_c,bool in_radians) const596 vsph_sph_box_2d vsph_sph_box_2d::transform(double t_theta, double t_phi,
597                                            double scale,  double theta_c,
598                                            double phi_c,  bool in_radians) const
599 {
600   //work in units of *this box
601   double d_th = t_theta, d_ph = t_phi;
602   if (this->in_radians_ && !in_radians) {
603     d_th /= vnl_math::deg_per_rad;
604     d_ph /= vnl_math::deg_per_rad;
605     phi_c/=vnl_math::deg_per_rad;
606     theta_c/=vnl_math::deg_per_rad;
607   }
608   if (!this->in_radians_ && in_radians) {
609     d_th *= vnl_math::deg_per_rad;
610     d_ph *= vnl_math::deg_per_rad;
611     phi_c   *=vnl_math::deg_per_rad;
612     theta_c *=vnl_math::deg_per_rad;
613   }
614   //first scale *this box and then rotate
615   //scaling is about the point theta_c and phi_c
616   //angular spread of both theta and phi is multiplied by scale
617   vsph_sph_point_2d center = this->center(in_radians_);
618   double min_th = min_theta(in_radians_), max_th = max_theta(in_radians_);
619   min_th = (min_th-theta_c)*scale + theta_c +d_th;
620   max_th = (max_th-theta_c)*scale + theta_c +d_th;
621 
622 
623   // don't allow transformations on theta that move outside range
624   if (min_th<0.0) min_th = 0.0;
625   if (max_th>pye())max_th = pye();
626 
627 
628   // for phi it is possible to scale beyond 360 degrees. Don't allow this.
629   // stop at the full circle and put phi_c at half angle opposite the
630   // circle cut.
631   double c_ph = center.phi_;
632   double ph_start=min_phi_, ph_end=max_phi_;
633   double difs = (vsph_utils::azimuth_diff(phi_c, ph_start, in_radians_));
634   double dife = (vsph_utils::azimuth_diff(phi_c, ph_end, in_radians_));
635   double difc = (vsph_utils::azimuth_diff(phi_c, c_ph, in_radians_));
636 
637   double s = scale;
638 
639   if (s*(difs+dife) > 2.0*pye()) {
640     ph_end = ph_start;
641   }
642   else {
643     //extend the start and end positions
644     difs *=s; dife*=s;difc*=s;
645     ph_start = phi_c + difs + d_ph;
646     ph_end =   phi_c + dife + d_ph;
647     c_ph = phi_c + difc + d_ph;
648     ph_start = reduce_phi(ph_start);
649     ph_end = reduce_phi(ph_end);
650     c_ph = reduce_phi(c_ph);
651   }
652   vsph_sph_box_2d rbox;
653   rbox.set(min_th, max_th, ph_start, ph_end, c_ph, in_radians_);
654   return rbox;
655 }
656 
planar_quads(std::vector<vgl_vector_3d<double>> & verts,std::vector<std::vector<int>> & quads,double tol) const657 void vsph_sph_box_2d::planar_quads(std::vector<vgl_vector_3d<double> >& verts,
658                                    std::vector<std::vector<int> >& quads,
659                                    double tol) const{
660   assert(tol >0.0 && tol < 1.0);
661   verts.clear(); quads.clear();
662   double temp = 1.0-tol;
663   double max_ang = 2.0*std::acos(temp);
664   if (!in_radians_)
665     max_ang *= vnl_math::deg_per_rad;
666   double min_th = min_theta(in_radians_), max_th = max_theta(in_radians_);
667   double theta_range =  std::fabs(max_th - min_th);
668   double ha1, ha2;
669   double min_ph = min_phi(in_radians_), max_ph = max_phi(in_radians_);
670   vsph_utils::half_angle(min_ph,max_ph, ha1, ha2, in_radians_);
671   double ha = ha2;
672   if (this->in_interval(ha1, in_radians_))
673     ha = ha1;
674   double ph_start, ph_end;
675   this->phi_bounds(ph_start, ph_end);
676   double phi_range = std::fabs(vsph_utils::azimuth_diff(ph_start, ha, in_radians_));
677   phi_range += std::fabs(vsph_utils::azimuth_diff(ha, ph_end, in_radians_));
678   double phi_last = ph_start + phi_range;
679   double n_thd = std::ceil(theta_range/max_ang);
680   double n_phd = std::ceil(phi_range/max_ang);
681   double th_inc = theta_range/n_thd, ph_inc = phi_range/n_phd;
682   int n_th = static_cast<int>(n_thd), n_ph = static_cast<int>(n_phd);
683   if (n_th == 0) n_th = 1;
684   if (n_ph == 0) n_ph = 1;
685   if (n_th ==1 && n_ph ==1) {//a single quad
686     vsph_sph_point_2d ul(min_th, ph_start, in_radians_);
687     vsph_sph_point_2d ur(min_th, ph_end, in_radians_);
688     vsph_sph_point_2d lr(max_th, ph_end, in_radians_);
689     vsph_sph_point_2d ll(max_th, ph_start, in_radians_);
690     vgl_vector_3d<double> vul = vsph_unit_sphere::cart_coord(ul);
691     vgl_vector_3d<double> vur = vsph_unit_sphere::cart_coord(ur);
692     vgl_vector_3d<double> vlr = vsph_unit_sphere::cart_coord(lr);
693     vgl_vector_3d<double> vll = vsph_unit_sphere::cart_coord(ll);
694     verts.resize(4);
695     int ill = 0, ilr = 1, iur =2 , iul = 3;//ccw order
696     verts[iul]=vul; verts[iur]=vur; verts[ilr]=vlr; verts[ill]=vll;
697     std::vector<int> quad(4);
698     quad[ill]=ill; quad[ilr]=ilr; quad[iur]=iur; quad[iul]=iul;
699     quads.push_back(quad);
700     return;
701   }
702   double th_end = max_th - DIST_TOL*th_inc;//take care of roundoff error
703   double ph_fin = phi_last -DIST_TOL*ph_inc;
704   double th_prev = min_th;
705   while (th_prev < th_end)
706   {
707     double ph_prev = ph_start;
708     double th_next = th_prev + th_inc;
709 
710     vsph_sph_point_2d ul(th_prev, reduce_phi(ph_prev), in_radians_);
711     vgl_vector_3d<double> vul = vsph_unit_sphere::cart_coord(ul);
712     int iul = verts.size();
713     verts.push_back(vul);
714 
715     vsph_sph_point_2d ll(th_next, reduce_phi(ph_prev), in_radians_);
716     vgl_vector_3d<double> vll = vsph_unit_sphere::cart_coord(ll);
717     int ill = verts.size();
718     verts.push_back(vll);
719 
720     while (ph_prev<ph_fin) {
721       double ph_next = ph_prev + ph_inc;
722       double ph_n=reduce_phi(ph_next);
723       vsph_sph_point_2d ur(th_prev, ph_n, in_radians_);
724       vgl_vector_3d<double> vur = vsph_unit_sphere::cart_coord(ur);
725       int iur = verts.size();
726       verts.push_back(vur);
727 
728       vsph_sph_point_2d lr(th_next, ph_n, in_radians_);
729       vgl_vector_3d<double> vlr = vsph_unit_sphere::cart_coord(lr);
730       int ilr = verts.size();
731       verts.push_back(vlr);
732 
733       std::vector<int> quad(4);
734       quad[0]=ill; quad[1]=ilr; quad[2]=iur; quad[3]=iul;
735       quads.push_back(quad);
736 
737       ph_prev = ph_next;
738       iul = iur; ill = ilr;
739     }
740     th_prev = th_next;
741   }
742 }
743 
sub_divide(std::vector<vsph_sph_box_2d> & sub_boxes,double min_ang) const744 bool vsph_sph_box_2d::sub_divide(std::vector<vsph_sph_box_2d>& sub_boxes,
745                                  double min_ang) const{
746   sub_boxes.clear();
747   double min_th = this->min_theta(in_radians_);
748   double max_th = this->max_theta(in_radians_);
749   double c_th = (min_th + max_th)/2.0;
750   double dth = std::fabs(max_th-c_th);
751   bool div_th = dth>min_ang;
752   double ph_start, ph_end;
753   this->phi_bounds(ph_start, ph_end);
754   double ha1, ha2;
755   vsph_utils::half_angle(ph_start,ph_end, ha1, ha2, in_radians_);
756   double ha = ha2;
757   if (this->in_interval(ha1, in_radians_))
758     ha = ha1;
759   double dph = std::fabs(vsph_utils::azimuth_diff(ph_start, ha, in_radians_));
760   bool div_ph = dph > min_ang;
761   if (!div_th&&!div_ph)
762     return false; // no division
763 
764   if (!div_th&div_ph) {
765     vsph_sph_box_2d box_phi_i, box_phi_j;
766     vsph_utils::half_angle(ph_start, ha, ha1, ha2, in_radians_);
767     double hai = ha2;
768     if (this->in_interval(ha1, in_radians_))
769       hai = ha1;
770     vsph_utils::half_angle(ha, ph_end, ha1, ha2, in_radians_);
771     double haj = ha2;
772     if (this->in_interval(ha1, in_radians_))
773       haj = ha1;
774     box_phi_i.set(min_th, max_th, ph_start, ha, hai, in_radians_);
775     box_phi_j.set(min_th, max_th, ha, ph_end, haj, in_radians_);
776     sub_boxes.resize(2);
777     sub_boxes[0]=box_phi_i; sub_boxes[1]=box_phi_j;
778     return true;
779   }
780   if (div_th&!div_ph) {
781     vsph_sph_box_2d box_th_i, box_th_j;
782     box_th_i.set(min_th, c_th, a_phi_, b_phi_, c_phi_, in_radians_);
783     box_th_j.set(c_th, max_th, a_phi_, b_phi_, c_phi_, in_radians_);
784     sub_boxes.resize(2);
785     sub_boxes[0]=box_th_i; sub_boxes[1]=box_th_j;
786     return true;
787   }
788   //final choice, sub-divide in both dimensions
789   vsph_sph_box_2d box_th0_ph0, box_th0_ph1, box_th1_ph0, box_th1_ph1;
790   vsph_utils::half_angle(ph_start, ha, ha1, ha2, in_radians_);
791   double hai = ha2;
792   if (this->in_interval(ha1, in_radians_))
793     hai = ha1;
794   vsph_utils::half_angle(ha, ph_end, ha1, ha2, in_radians_);
795   double haj = ha2;
796   if (this->in_interval(ha1, in_radians_))
797     haj = ha1;
798   box_th0_ph0.set(min_th, c_th, ph_start, ha, hai, in_radians_);
799   box_th0_ph1.set(min_th, c_th, ha, ph_end, haj, in_radians_);
800   box_th1_ph0.set(c_th, max_th, ph_start, ha, hai, in_radians_);
801   box_th1_ph1.set(c_th, max_th, ha, ph_end, haj, in_radians_);
802   sub_boxes.resize(4);
803   sub_boxes[0]=box_th0_ph0;   sub_boxes[1]=box_th0_ph1;
804   sub_boxes[2]=box_th1_ph0;   sub_boxes[3]=box_th1_ph1;
805   return true;
806 }
807 
print(std::ostream & os,bool in_radians) const808 void vsph_sph_box_2d::print(std::ostream& os, bool in_radians) const
809 {
810   os << " vsph_sph_box_2d:[(" << min_theta(in_radians) << ' '
811      << min_phi(in_radians) << ")->(" << max_theta(in_radians)
812      << ' ' << max_phi(in_radians) << ")]\n";
813 }
814 
display_box(std::ostream & os,float r,float g,float b,double tol,double factor) const815 void vsph_sph_box_2d::display_box(std::ostream& os,
816                                   float r, float g, float b,
817                                   double tol, double factor) const
818 {
819   std::vector<vgl_vector_3d<double> > verts;
820   std::vector<std::vector<int> > quads;
821   this->planar_quads(verts, quads, tol);
822   os << "Shape {\n"
823      <<"  appearance Appearance{\n"
824      <<"    material Material {\n"
825      <<"     diffuseColor  " << r << ' ' << g << ' ' << b << '\n'
826      <<"          }\n"
827      <<"    }\n"
828      << " geometry IndexedFaceSet\n"
829      << "  {\n"
830      << "   coord Coordinate{\n"
831      << "     point [\n";
832   unsigned n = verts.size();
833   for (unsigned iv = 0; iv<n; ++iv) {
834     vgl_vector_3d<double>& v = verts[iv];
835     os << v.x() * factor<< ',' << v.y()* factor << ',' << v.z()* factor;
836     if (iv < (n-1)) os << ",\n";
837     else os << '\n';
838   }
839   os << "      ]\n"
840      << "    }\n"
841      << "  coordIndex [\n";
842   unsigned nq = quads.size();
843   for (unsigned iq = 0; iq<nq; ++iq) {
844     std::vector<int> quad = quads[iq];
845     os << quad[0] << ',' << quad[1] << ',' << quad[2] << ','
846        << quad[3] << ", -1";
847     if (iq < (nq-1)) os << ",\n";
848     else os << '\n';
849   }
850   os << "   ]\n"
851      << " }\n"
852      << "}\n";
853 }
854 
display_boxes(std::string const & path,std::vector<vsph_sph_box_2d> const & boxes,std::vector<std::vector<float>> colors,double tol,double factor)855 void vsph_sph_box_2d::display_boxes(std::string const& path,
856                                     std::vector<vsph_sph_box_2d> const& boxes,
857                                     std::vector<std::vector<float> > colors,
858                                     double tol,double factor ) {
859   std::ofstream os(path.c_str());
860   if (!os.is_open())
861     return;
862   bvrml_write::write_vrml_header(os);
863   unsigned nb = boxes.size();
864   unsigned nc = colors.size();
865   assert(nc == nb);
866   for (unsigned i = 0; i<nb; ++i) {
867     std::vector<float> c = colors[i];
868     boxes[i].display_box(os, c[0], c[1],c[2],tol,factor);
869   }
870   os.close();
871 }
872 
b_read(vsl_b_istream &)873 void vsph_sph_box_2d::b_read(vsl_b_istream& /*is*/)
874 {
875 #if 0
876   short version;
877   vsl_b_read(is, version);
878   switch (version) {
879   case 1:
880     vsl_b_read(is,in_radians_);
881     vsl_b_read(is, min_pos_[0]); // theta
882     vsl_b_read(is, min_pos_[1]); // phi
883     vsl_b_read(is, max_pos_[0]);
884     vsl_b_read(is, max_pos_[1]);
885   }
886 #endif
887 }
888 
b_write(vsl_b_ostream &)889 void vsph_sph_box_2d::b_write(vsl_b_ostream& /*os*/)
890 {
891 #if 0
892   vsl_b_write(os, version());
893   vsl_b_write(os, in_radians_);
894   vsl_b_write(os, min_pos_[0]); // theta
895   vsl_b_write(os, min_pos_[1]); // phi
896   vsl_b_write(os, max_pos_[0]);
897   vsl_b_write(os, max_pos_[1]);
898 #endif
899 }
900 
901 #if 0
902 bool intersection(vsph_sph_box_2d const& b1, vsph_sph_box_2d const& b2,
903                   std::vector<vsph_sph_box_2d>& boxes)
904 {
905   bool in_radians = b1.in_radians();
906   vsph_sph_box_2d rbox(in_radians);
907   double theta_min =
908     b1.min_theta(in_radians) < b2.min_theta(in_radians) ?
909     b2.min_theta(in_radians) : b1.min_theta(in_radians);
910 
911   double theta_max =
912     b1.max_theta(in_radians) < b2.max_theta(in_radians) ?
913     b1.max_theta(in_radians) : b2.max_theta(in_radians);
914   // empty box.
915   if (theta_max <= theta_min)
916     return false;
917   // takes 467 msecs for 10^7 intersections
918   double b2_min_ph = b2.min_phi(in_radians), b1_min_ph = b1.min_phi(in_radians);
919   double b2_max_ph = b2.max_phi(in_radians), b1_max_ph = b1.max_phi(in_radians);
920   bool b2min_in_b1 = b1.in_interval(b2_min_ph, in_radians);
921   bool b1min_in_b2 = b2.in_interval(b1_min_ph, in_radians);
922   bool b2max_in_b1 = b1.in_interval(b2_max_ph, in_radians);
923   bool b1max_in_b2 = b2.in_interval(b1_max_ph, in_radians);
924 
925   // no overlap return an empty box
926   if (!b2min_in_b1&&!b1min_in_b2&&!b2max_in_b1&&!b1max_in_b2)
927     return false;
928   double ha1, ha2;
929 
930   if (!b1min_in_b2 && !b1max_in_b2 && b2min_in_b1 && b2max_in_b1) {
931     vsph_utils::half_angle(b2.min_phi(in_radians), b2.max_phi(in_radians),
932                            ha1, ha2, in_radians);
933     if (b2.in_interval(ha1, in_radians)&& b2.in_interval(ha1, in_radians))
934       rbox.set(theta_min, theta_max, b2.min_phi(in_radians),
935                b2.max_phi(in_radians),ha1,in_radians);
936     else
937       rbox.set(theta_min, theta_max, b2.min_phi(in_radians),
938                b2.max_phi(in_radians),ha2,in_radians);
939     boxes.resize(1);
940     boxes[0]=rbox;
941     return true;
942   }
943 
944   if (b1min_in_b2 && !b1max_in_b2 && !b2min_in_b1 && b2max_in_b1) {
945     vsph_utils::half_angle(b1.min_phi(in_radians), b2.max_phi(in_radians),
946                            ha1, ha2, in_radians);
947     if (b1.in_interval(ha1, in_radians)&& b2.in_interval(ha1, in_radians))
948       rbox.set(theta_min, theta_max, b1.min_phi(in_radians),
949                b2.max_phi(in_radians),ha1,in_radians);
950     else
951       rbox.set(theta_min, theta_max, b1.min_phi(in_radians),
952                b2.max_phi(in_radians),ha2,in_radians);
953     boxes.resize(1);
954     boxes[0]=rbox;
955     return true;
956   }
957 
958   if (!b1min_in_b2 && b1max_in_b2 && b2min_in_b1 && !b2max_in_b1) {
959     vsph_utils::half_angle(b2.min_phi(in_radians), b1.max_phi(in_radians),
960                            ha1, ha2, in_radians);
961     if (b1.in_interval(ha1,in_radians)&& b2.in_interval(ha1,in_radians))
962       rbox.set(theta_min, theta_max, b2.min_phi(in_radians),
963                b1.max_phi(in_radians),ha1,in_radians);
964     else
965       rbox.set(theta_min, theta_max, b2.min_phi(in_radians),
966                b1.max_phi(in_radians),ha2,in_radians);
967     boxes.resize(1);
968     boxes[0]=rbox;
969     return true;
970   }
971 
972   if (b1min_in_b2 && b1max_in_b2&&!b2min_in_b1&&!b2max_in_b1) {
973     vsph_utils::half_angle(b1.min_phi(in_radians), b1.max_phi(in_radians),
974                            ha1, ha2, in_radians);
975     if (b1.in_interval(ha1,in_radians)&& b2.in_interval(ha1,in_radians))
976       rbox.set(theta_min, theta_max, b1.min_phi(in_radians),
977                b1.max_phi(in_radians),ha1,in_radians);
978     else
979       rbox.set(theta_min, theta_max, b1.min_phi(in_radians),
980                b1.max_phi(in_radians),ha2,in_radians);
981     boxes.resize(1);
982     boxes[0]=rbox;
983     return true;
984   }
985 
986   if (!b1min_in_b2 && !b1max_in_b2 && b2min_in_b1 && b2max_in_b1) {
987     vsph_utils::half_angle(b2.min_phi(in_radians), b2.max_phi(in_radians),
988                            ha1, ha2, in_radians);
989     if (b2.in_interval(ha1,in_radians)&& b1.in_interval(ha1,in_radians))
990       rbox.set(theta_min, theta_max, b2.min_phi(in_radians),
991                b2.max_phi(in_radians),ha1,in_radians);
992     else
993       rbox.set(theta_min, theta_max, b2.min_phi(in_radians),
994                b2.max_phi(in_radians),ha2,in_radians);
995     boxes.resize(1);
996     boxes[0]=rbox;
997     return true;
998   }
999   // This condition produces two boxes (b1min=>b2max  b2min=>b1max)
1000   if (b1min_in_b2 && b1max_in_b2 && b2min_in_b1 && b2max_in_b1) {
1001     vsph_sph_box_2d rbox2(in_radians);
1002     boxes.resize(2);
1003     vsph_utils::half_angle(b1.min_phi(in_radians), b2.max_phi(in_radians),
1004                            ha1, ha2, in_radians);
1005     if (b2.in_interval(ha1,in_radians)&& b1.in_interval(ha1,in_radians))
1006       rbox.set(theta_min, theta_max, b1.min_phi(in_radians),
1007                b2.max_phi(in_radians),ha1,in_radians);
1008     else
1009       rbox.set(theta_min, theta_max, b1.min_phi(in_radians),
1010                b2.max_phi(in_radians),ha2,in_radians);
1011     boxes[0]=rbox;
1012     vsph_utils::half_angle(b2.min_phi(in_radians), b1.max_phi(in_radians),
1013                            ha1, ha2, in_radians);
1014     if (b2.in_interval(ha1,in_radians)&& b1.in_interval(ha1,in_radians))
1015       rbox2.set(theta_min, theta_max, b2.min_phi(in_radians),
1016                 b1.max_phi(in_radians),ha1,in_radians);
1017     else
1018       rbox2.set(theta_min, theta_max, b2.min_phi(in_radians),
1019                 b1.max_phi(in_radians),ha2,in_radians);
1020     boxes[1]=rbox2;
1021     return true;
1022   }
1023   std::cout << "IMPOSSIBLE INTERSECTION CONDITION NOT HANDLED!!\n";
1024   assert(false); //shouldn't happen
1025   return false;
1026 }
1027 #endif
1028 
intersection(vsph_sph_box_2d const & b1,vsph_sph_box_2d const & b2,std::vector<vsph_sph_box_2d> & boxes)1029 bool intersection(vsph_sph_box_2d const& b1, vsph_sph_box_2d const& b2,
1030                   std::vector<vsph_sph_box_2d>& boxes)
1031 {
1032   if (b1 == b2){
1033     boxes.resize(1);
1034     boxes[0]=b1;
1035     return true;
1036   }
1037   bool in_radians = b1.in_radians();
1038   double theta_min =
1039     b1.min_theta(in_radians) < b2.min_theta(in_radians) ?
1040     b2.min_theta(in_radians) : b1.min_theta(in_radians);
1041 
1042   double theta_max =
1043     b1.max_theta(in_radians) < b2.max_theta(in_radians) ?
1044     b1.max_theta(in_radians) : b2.max_theta(in_radians);
1045   // empty box.
1046   if (theta_max <= theta_min)
1047     return false;
1048   double b2_min_ph = b2.min_phi(in_radians), b1_min_ph = b1.min_phi(in_radians);
1049   double b2_max_ph = b2.max_phi(in_radians), b1_max_ph = b1.max_phi(in_radians);
1050 
1051   bool b2min_in_b1 = b1.in_interval(b2_min_ph, in_radians);
1052   bool b1min_in_b2 = b2.in_interval(b1_min_ph, in_radians);
1053   bool b2max_in_b1 = b1.in_interval(b2_max_ph, in_radians);
1054   bool b1max_in_b2 = b2.in_interval(b1_max_ph, in_radians);
1055 
1056   unsigned short flags = 0;
1057   if (b2max_in_b1) flags = flags | 1;
1058   if (b2min_in_b1) flags = flags | 2;
1059   if (b1max_in_b2) flags = flags | 4;
1060   if (b1min_in_b2) flags = flags | 8;
1061   double ha1, ha2;
1062   switch (flags)
1063   {
1064     // no intersection
1065    case 0:{
1066     return false;
1067    }
1068     // b2 contained in b1
1069    case 3:{
1070     boxes.resize(1);
1071     boxes[0].set(theta_min, theta_max, b2_min_ph,
1072                  b2_max_ph, b2.c_phi(in_radians),in_radians);
1073     return true;
1074    }
1075     //  b2_min => b1_max
1076    case 6:{
1077     boxes.resize(1);
1078     vsph_utils::half_angle(b2_min_ph, b1_max_ph, ha1, ha2, in_radians);
1079     //either ha1 or  ha2 has to be in both box intervals
1080     if (b1.in_interval(ha1,in_radians)&& b2.in_interval(ha1,in_radians))
1081       boxes[0].set(theta_min, theta_max, b2_min_ph, b1_max_ph,ha1,in_radians);
1082     else
1083       boxes[0].set(theta_min, theta_max, b2_min_ph, b1_max_ph, ha2,in_radians);
1084     return true;
1085    }
1086     //  b1_min => b2_max
1087    case 9:{
1088     boxes.resize(1);
1089     vsph_utils::half_angle(b1_min_ph, b2_max_ph, ha1, ha2, in_radians);
1090     //eithr ha1 or ha2 has to be in both intervals
1091     if (b1.in_interval(ha1, in_radians)&& b2.in_interval(ha1, in_radians))
1092       boxes[0].set(theta_min, theta_max, b1_min_ph, b2_max_ph, ha1,in_radians);
1093     else
1094 
1095       boxes[0].set(theta_min, theta_max, b1_min_ph, b2_max_ph, ha2,in_radians);
1096     return true;
1097    }
1098     // b1 contained in b2
1099   case 12:{
1100     boxes.resize(1);
1101     boxes[0].set(theta_min, theta_max, b1_min_ph, b1_max_ph,
1102                  b1.c_phi(in_radians),in_radians);
1103     return true;
1104    }
1105 
1106   // This condition produces two boxes (b1min=>b2max  b2min=>b1max)
1107    case 15:{
1108     boxes.resize(2);
1109     vsph_utils::half_angle(b1_min_ph, b2_max_ph, ha1, ha2, in_radians);
1110     if (b2.in_interval(ha1,in_radians)&& b1.in_interval(ha1,in_radians))
1111       boxes[0].set(theta_min, theta_max, b1_min_ph, b2_max_ph,ha1,in_radians);
1112     else
1113       boxes[0].set(theta_min, theta_max, b1_min_ph, b2_max_ph,ha2,in_radians);
1114 
1115     vsph_utils::half_angle(b2_min_ph, b1_max_ph, ha1, ha2, in_radians);
1116     if (b2.in_interval(ha1,in_radians)&& b1.in_interval(ha1,in_radians))
1117       boxes[1].set(theta_min, theta_max, b2_min_ph, b1_max_ph, ha1,in_radians);
1118     else
1119       boxes[1].set(theta_min, theta_max, b2_min_ph, b1_max_ph, ha2,in_radians);
1120     return true;
1121    }
1122    default:
1123     std::cout << "IMPOSSIBLE INTERSECTION CONDITION NOT HANDLED!!\n";
1124     assert(false); //shouldn't happen
1125     return false;
1126   }
1127 }
1128 
intersection_area(vsph_sph_box_2d const & b1,vsph_sph_box_2d const & b2)1129 double intersection_area(vsph_sph_box_2d const& b1, vsph_sph_box_2d const& b2)
1130 {
1131   if (b1 == b2)
1132     return b1.area();
1133   bool in_radians = true;
1134   double theta_min =
1135     b1.min_theta(in_radians) < b2.min_theta(in_radians) ?
1136     b2.min_theta(in_radians) : b1.min_theta(in_radians);
1137 
1138   double theta_max =
1139     b1.max_theta(in_radians) < b2.max_theta(in_radians) ?
1140     b1.max_theta(in_radians) : b2.max_theta(in_radians);
1141   // empty box.
1142   if (theta_max <= theta_min)
1143     return 0.0;
1144   double a = std::fabs(std::cos(theta_min)-std::cos(theta_max));
1145 
1146   double b2_min_ph = b2.min_phi(in_radians), b1_min_ph = b1.min_phi(in_radians);
1147   double b2_max_ph = b2.max_phi(in_radians), b1_max_ph = b1.max_phi(in_radians);
1148 
1149   bool b2min_in_b1 = b1.in_interval(b2_min_ph, in_radians);
1150   bool b1min_in_b2 = b2.in_interval(b1_min_ph, in_radians);
1151   bool b2max_in_b1 = b1.in_interval(b2_max_ph, in_radians);
1152   bool b1max_in_b2 = b2.in_interval(b1_max_ph, in_radians);
1153 
1154   unsigned short flags = 0;
1155   if (b2max_in_b1) flags = flags | 1;
1156   if (b2min_in_b1) flags = flags | 2;
1157   if (b1max_in_b2) flags = flags | 4;
1158   if (b1min_in_b2) flags = flags | 8;
1159   double ha1, ha2, dph =0.0;
1160   switch (flags)
1161   {
1162     // no intersection
1163     case 0:{
1164       return 0.0;
1165     }
1166       // b2 contained in b1
1167     case 3:{
1168       vsph_utils::half_angle(b2_min_ph, b2_max_ph, ha1, ha2, in_radians);
1169       //either ha1 or  ha2 has to be in the box interval
1170       if (b2.in_interval(ha1,in_radians))
1171         dph = vsph_utils::arc_len(b2_min_ph, b2_max_ph,ha1);
1172       else
1173         dph =  vsph_utils::arc_len(b2_min_ph, b2_max_ph, ha2);
1174       return dph*a;
1175     }
1176       //  b2_min => b1_max
1177     case 6:{
1178       vsph_utils::half_angle(b2_min_ph, b1_max_ph, ha1, ha2, in_radians);
1179       //either ha1 or  ha2 has to be in both box intervals
1180       if (b1.in_interval(ha1,in_radians)&& b2.in_interval(ha1,in_radians))
1181         dph = vsph_utils::arc_len(b2_min_ph, b1_max_ph,ha1);
1182       else
1183         dph =  vsph_utils::arc_len(b2_min_ph, b1_max_ph, ha2);
1184       return dph*a;
1185     }
1186       //  b1_min => b2_max
1187     case 9:{
1188       vsph_utils::half_angle(b1_min_ph, b2_max_ph, ha1, ha2, in_radians);
1189       //eithr ha1 or ha2 has to be in both intervals
1190       if (b1.in_interval(ha1, in_radians)&& b2.in_interval(ha1, in_radians))
1191         dph = vsph_utils::arc_len(b1_min_ph, b2_max_ph, ha1);
1192       else
1193         dph = vsph_utils::arc_len(b1_min_ph, b2_max_ph, ha2);
1194       return dph*a;
1195     }
1196       // b1 contained in b2
1197     case 12:{
1198       vsph_utils::half_angle(b1_min_ph, b1_max_ph, ha1, ha2, in_radians);
1199       //either ha1 or  ha2 has to be in the box interval
1200       if (b1.in_interval(ha1,in_radians))
1201         dph = vsph_utils::arc_len(b1_min_ph, b1_max_ph,ha1);
1202       else
1203         dph =  vsph_utils::arc_len(b1_min_ph, b1_max_ph, ha2);
1204       return dph*a;
1205     }
1206 
1207     // This condition produces two boxes (b1min=>b2max  b2min=>b1max)
1208     case 15:{
1209       double dph2 =0.0;
1210       vsph_utils::half_angle(b1_min_ph, b2_max_ph, ha1, ha2, in_radians);
1211       if (b2.in_interval(ha1,in_radians)&& b1.in_interval(ha1,in_radians))
1212         dph = vsph_utils::arc_len(b1_min_ph, b2_max_ph,ha1);
1213       else
1214         dph = vsph_utils::arc_len(b1_min_ph, b2_max_ph,ha2);
1215 
1216       vsph_utils::half_angle(b2_min_ph, b1_max_ph, ha1, ha2, in_radians);
1217       if (b2.in_interval(ha1,in_radians)&& b1.in_interval(ha1,in_radians))
1218         dph2 = vsph_utils::arc_len(b2_min_ph, b1_max_ph, ha1);
1219       else
1220         dph2 = vsph_utils::arc_len(b2_min_ph, b1_max_ph, ha2);
1221       return a*(dph+dph2);
1222     }
1223     default:
1224       std::cout << "IMPOSSIBLE INTERSECTION CONDITION NOT HANDLED!!\n";
1225       assert(false); //shouldn't happen
1226       return 0.0;
1227   }
1228 }
1229 
operator <<(std::ostream & os,vsph_sph_box_2d const & p)1230 std::ostream& operator<<(std::ostream& os, vsph_sph_box_2d const& p)
1231 {
1232   p.print(os);
1233   return os;
1234 }
1235