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