00001 #ifndef bsta_spherical_histogram_txx_
00002 #define bsta_spherical_histogram_txx_
00003
00004
00005 #include "bsta_spherical_histogram.h"
00006
00007 #include <vcl_cmath.h>
00008 #include <vcl_iostream.h>
00009 #include <vcl_cassert.h>
00010 #include <vnl/vnl_math.h>
00011 #include <vnl/vnl_vector.h>
00012
00013
00014
00015
00016 template <class T>
00017 static bool in_interval(T start, T range, T angle)
00018 {
00019 T end = start + range;
00020 bool no_cut = (end <= T(360));
00021 if (no_cut) {
00022 return angle >= start && angle < end;
00023 }
00024
00025 if (angle >= start && angle<=T(360))
00026 return true;
00027 T branch_end = end - T(360);
00028 if (angle >= 0 && angle < branch_end)
00029 return true;
00030 return false;
00031 }
00032
00033 template <class T>
00034 static T start_90_180(T start, T range)
00035 {
00036 return -(start+range) + T(90);
00037 }
00038
00039
00040
00041
00042
00043 template <class T>
00044 static T azimuth_diff(T a, T b, T two_pi)
00045 {
00046 T x0 = a, x1 = b, sign = T(1);
00047 if (a>b) {x0 = b; x1 = a; sign = -sign;}
00048 T a1 = x1-x0;
00049 T a2 = two_pi - a1;
00050 if (a1>a2) return -sign*a2;
00051 return sign*a1;
00052 }
00053
00054 template <class T>
00055 bsta_spherical_histogram<T>::bsta_spherical_histogram()
00056 : n_azimuth_(0), n_elevation_(0),
00057 azimuth_start_(0), azimuth_range_(0),
00058 elevation_start_(0), elevation_range_(0),
00059 az_branch_cut_(B_180_180), el_poles_(B_90_90),
00060 units_(DEG), total_counts_valid_(false), total_counts_(0)
00061 {
00062 }
00063
00064 template <class T>
00065 bsta_spherical_histogram<T>::
00066 bsta_spherical_histogram(unsigned n_azimuth, unsigned n_elevation,
00067 T azimuth_start, T azimuth_range, T elevation_start,
00068 T elevation_range, ang_units units,
00069 angle_bounds az_branch_cut, angle_bounds el_poles)
00070 : n_azimuth_(n_azimuth), n_elevation_(n_elevation),
00071 azimuth_start_(azimuth_start), azimuth_range_(azimuth_range),
00072 elevation_start_(elevation_start), elevation_range_(elevation_range),
00073 az_branch_cut_(az_branch_cut), el_poles_(el_poles),
00074 units_(units), total_counts_valid_(false), total_counts_(0)
00075 {
00076 assert(n_azimuth>0&&n_elevation>0);
00077
00078 if (units_ == RADIANS) {
00079 azimuth_start_ = rad_to_deg(azimuth_start_);
00080 azimuth_range_ = rad_to_deg(azimuth_range_);
00081 elevation_start_ = rad_to_deg(elevation_start_);
00082 elevation_range_ = rad_to_deg(elevation_range_);
00083 }
00084
00085 if (az_branch_cut == B_180_180)
00086 if (azimuth_start_<T(0))
00087 azimuth_start_ = azimuth_start_+ static_cast<T>(360);
00088
00089
00090 if (el_poles_ == B_90_90)
00091 elevation_start_ =
00092 start_90_180(elevation_start_,elevation_range_);
00093
00094 delta_az_ = azimuth_range_/n_azimuth_;
00095 delta_el_ = elevation_range_/n_elevation_;
00096 }
00097
00098
00099 template <class T>
00100 T bsta_spherical_histogram<T>::azimuth_start() const
00101 {
00102 T az_start = azimuth_start_;
00103 if (az_branch_cut_==B_180_180)
00104 if (az_start >=T(180))
00105 az_start -= T(360);
00106 if (units_ == RADIANS)
00107 az_start = deg_to_rad(az_start);
00108 return az_start;
00109 }
00110
00111 template <class T>
00112 T bsta_spherical_histogram<T>::azimuth_range() const
00113 {
00114 if (units_ == RADIANS)
00115 return deg_to_rad(azimuth_range_);
00116 return azimuth_range_;
00117 }
00118
00119
00120 template <class T>
00121 T bsta_spherical_histogram<T>::elevation_start() const
00122 {
00123 T el_start = elevation_start_;
00124 if (el_poles_==B_90_90)
00125 el_start = start_90_180(el_start, elevation_range_);
00126 if (units_ == RADIANS)
00127 el_start = deg_to_rad(el_start);
00128 return el_start;
00129 }
00130
00131 template <class T>
00132 T bsta_spherical_histogram<T>::elevation_range() const
00133 {
00134 if (units_ == RADIANS)
00135 return deg_to_rad(elevation_range_);
00136 return elevation_range_;
00137 }
00138
00139 template <class T>
00140 T bsta_spherical_histogram<T>::azimuth_center(int azimuth_index) const
00141 {
00142 double start = azimuth_index*delta_az_ + azimuth_start_;
00143 double end = start + delta_az_;
00144 double mid = 0.5*(start + end);
00145 if (mid>=360.0)
00146 mid -= 360.0;
00147 if (az_branch_cut_==B_180_180 && mid > 180.0)
00148 mid -= 360.0;
00149 T middle = static_cast<T>(mid);
00150 if (units_ == RADIANS)
00151 return deg_to_rad(middle);
00152 return middle;
00153 }
00154
00155 template <class T>
00156 T bsta_spherical_histogram<T>::elevation_center(int elevation_index) const
00157 {
00158 double start = elevation_index*delta_el_;
00159 double end = start + delta_el_;
00160 double mid = 0.5*(start + end);
00161 if (el_poles_ == B_90_90)
00162 mid = 90.0-mid;
00163 T middle = static_cast<T>(mid);
00164 if (units_ == RADIANS)
00165 return deg_to_rad(middle);
00166 return middle;
00167 }
00168
00169 template <class T>
00170 void bsta_spherical_histogram<T>::
00171 center(int linear_index, T& az_center, T& el_center)
00172 {
00173
00174 int el_index = linear_index/n_azimuth_;
00175 int az_index = linear_index%n_azimuth_;
00176 az_center = azimuth_center(az_index);
00177 el_center = elevation_center(el_index);
00178 }
00179
00180 template <class T>
00181 void bsta_spherical_histogram<T>::
00182 convert_to_cartesian(T azimuth, T elevation, T& x, T& y, T& z) const
00183 {
00184 T az = azimuth, el=elevation;
00185 if (units_==DEG) {
00186 az = deg_to_rad(az);
00187 el = deg_to_rad(el);
00188 }
00189
00190 if (az_branch_cut_ == B_0_360)
00191 if (az>static_cast<T>(vnl_math::pi))
00192 az -= static_cast<T>(2.0*vnl_math::pi);
00193 if (el_poles_ == B_90_90)
00194 el = -el + static_cast<T>(vnl_math::pi/2.0);
00195
00196 T s = vcl_sin(el);
00197 x = s*vcl_cos(az);
00198 y = s*vcl_sin(az);
00199 z = vcl_cos(el);
00200 }
00201
00202 template <class T>
00203 void bsta_spherical_histogram<T>::
00204 convert_to_spherical(T x, T y, T z, T& azimuth, T& elevation) const
00205 {
00206
00207
00208
00209 if (vcl_fabs(z-T(1))<1e-8) {
00210 azimuth = T(0);
00211 if (el_poles_ == B_90_90)
00212 elevation = T(90);
00213 else
00214 elevation = T(0);
00215 if (units_ == RADIANS)
00216 elevation = deg_to_rad(elevation);
00217 return;
00218 }
00219 if (vcl_fabs(z+T(1))<1e-8) {
00220 azimuth = T(0);
00221 if (el_poles_ == B_90_90)
00222 elevation = -T(90);
00223 else
00224 elevation = T(180);
00225 if (units_ == RADIANS)
00226 elevation = deg_to_rad(elevation);
00227 return;
00228 }
00229 elevation = vcl_acos(z);
00230 T s = vcl_sin(elevation);
00231 T xa = x/s;
00232 T ya = y/s;
00233 azimuth = vcl_atan2(ya, xa);
00234 if (az_branch_cut_ == B_0_360)
00235 if (azimuth<0) azimuth += static_cast<T>(2.0*vnl_math::pi);
00236 if (el_poles_ == B_90_90)
00237 elevation = -elevation + static_cast<T>(0.5*vnl_math::pi);
00238 if (units_ == DEG) {
00239 elevation = rad_to_deg(elevation);
00240 azimuth = rad_to_deg(azimuth);
00241 }
00242 return;
00243 }
00244
00245 template <class T>
00246 int bsta_spherical_histogram<T>::azimuth_index(T azimuth) const
00247 {
00248 if (n_azimuth_==0) return -1;
00249
00250 T conv_az = azimuth;
00251 if (units_==RADIANS)
00252 conv_az = rad_to_deg(conv_az);
00253
00254 if (az_branch_cut_ == B_180_180)
00255 if (conv_az < 0)
00256 conv_az += T(360);
00257 for (unsigned i = 0; i<n_azimuth_; ++i) {
00258 T start = static_cast<T>(i*delta_az_)+ azimuth_start_;
00259 if (in_interval(start, delta_az_, conv_az))
00260 {
00261 return i;
00262 }
00263 }
00264 return -1;
00265 }
00266
00267 template <class T>
00268 int bsta_spherical_histogram<T>::elevation_index(T elevation) const
00269 {
00270 if (n_elevation_==0) return -1;
00271
00272 T conv_el = elevation;
00273 if (units_==RADIANS)
00274 conv_el = rad_to_deg(conv_el);
00275
00276
00277 if (el_poles_ == B_90_90) {
00278 conv_el = -conv_el + T(90);
00279 }
00280 for (unsigned i = 0; i<n_elevation_; ++i)
00281 if (static_cast<T>((i+1)*delta_el_) + elevation_start_ >= conv_el)
00282 {
00283 return i;
00284 }
00285 return -1;
00286 }
00287
00288 template <class T>
00289 void bsta_spherical_histogram<T>::
00290 azimuth_interval(int azimuth_index, T& azimuth_start, T& azimuth_range) const
00291 {
00292 if (n_azimuth_==0) {
00293 azimuth_start = T(0);
00294 azimuth_range = T(0);
00295 return;
00296 }
00297 T az_start = static_cast<T>(azimuth_index*delta_az_)+azimuth_start_;
00298
00299 if (az_branch_cut_ == B_180_180) {
00300 if (az_start >= T(180))
00301 az_start -= T(360);
00302 }
00303 else
00304 if (az_start>=T(360)) az_start -=T(360);
00305
00306
00307 if (units_ == RADIANS) {
00308 azimuth_start = deg_to_rad(az_start);
00309 azimuth_range = deg_to_rad(delta_az_);
00310 return;
00311 }
00312 azimuth_start = az_start;
00313 azimuth_range = delta_az_;
00314 }
00315
00316 template <class T>
00317 void bsta_spherical_histogram<T>::
00318 elevation_interval(int elevation_index, T& elevation_start, T& elevation_range) const
00319 {
00320 if (n_elevation_==0) {
00321 elevation_start = T(0);
00322 elevation_range = T(0);
00323 return;
00324 }
00325
00326 T el_start = static_cast<T>(elevation_index*delta_el_);
00327 if (el_poles_ == B_90_90)
00328 el_start = start_90_180(el_start, delta_el_);
00329
00330 if (units_ == RADIANS) {
00331 elevation_start = deg_to_rad(el_start);
00332 elevation_range = deg_to_rad(delta_el_);
00333 return;
00334 }
00335 elevation_start = el_start;
00336 elevation_range = delta_el_;
00337 }
00338
00339 template <class T>
00340 void bsta_spherical_histogram<T>::
00341 upcount(T azimuth, T elevation, T mag)
00342 {
00343 int az_indx = azimuth_index(azimuth);
00344 int el_indx = elevation_index(elevation);
00345 int lidx = linear_index(az_indx, el_indx);
00346 if (!counts_[lidx])
00347 counts_[lidx]=T(0);
00348 counts_[lidx]+=mag;
00349 total_counts_valid_ = false;
00350 }
00351
00352 template <class T>
00353 void bsta_spherical_histogram<T>::
00354 upcount_weighted_by_area(T azimuth, T elevation, T mag)
00355 {
00356 int el_indx = elevation_index(elevation);
00357 double ecnt = elevation_center(el_indx);
00358 T s = static_cast<T>(vcl_fabs(vcl_sin(ecnt)));
00359 if (s>0)
00360 mag /= s;
00361 upcount(azimuth, elevation, mag);
00362 }
00363
00364 template <class T>
00365 T bsta_spherical_histogram<T>::total_counts()
00366 {
00367 if (!total_counts_valid_) {
00368 total_counts_ = T(0);
00369 typename vcl_map<int, T>::iterator cit = counts_.begin();
00370 for (; cit != counts_.end(); ++cit)
00371 total_counts_ += (*cit).second;
00372 total_counts_valid_ = true;
00373 }
00374 return total_counts_;
00375 }
00376
00377 template <class T>
00378 T bsta_spherical_histogram<T>::p(int azimuth_index, int elevation_index)
00379 {
00380 T tcnts = this->total_counts();
00381 if (tcnts == T(0)) return T(0);
00382 if (elevation_index<0||elevation_index>=static_cast<int>(n_elevation())||
00383 azimuth_index<0||azimuth_index>=static_cast<int>(n_azimuth()))
00384 return T(0);
00385 int lidx = linear_index(azimuth_index, elevation_index);
00386 if (!counts_[lidx])
00387 return 0;
00388 return counts_[lidx]/tcnts;
00389 }
00390
00391 template <class T>
00392 void bsta_spherical_histogram<T>::mean(T& mean_az, T& mean_el)
00393 {
00394
00395
00396 double mean_x = 0.0, mean_y = 0.0, mean_z = 0.0;
00397 for (int el = 0; el<static_cast<int>(n_elevation_); ++el) {
00398 T ec = elevation_center(el);
00399 for (int az = 0; az<static_cast<int>(n_azimuth_); ++az) {
00400 T ac = azimuth_center(az);
00401 T x, y, z;
00402 convert_to_cartesian(ac, ec, x, y, z);
00403 T pc = p(az, el);
00404 mean_x += pc*x; mean_y += pc*y; mean_z += pc*z;
00405 }
00406 }
00407 double length = vcl_sqrt(mean_x*mean_x + mean_y*mean_y + mean_z*mean_z);
00408 if (length<1.0e-8) {
00409 mean_az = 0;
00410 mean_el = 0;
00411 return;
00412 }
00413 mean_x /= length; mean_y /= length; mean_z /= length;
00414 convert_to_spherical(static_cast<T>(mean_x), static_cast<T>(mean_y),
00415 static_cast<T>(mean_z), mean_az, mean_el);
00416 }
00417
00418 template <class T>
00419 vnl_matrix_fixed<T, 2, 2> bsta_spherical_histogram<T>::covariance_matrix()
00420 {
00421 double mean_x = T(0), mean_y = T(0) , mean_z = T(0);
00422 T two_pi = T(360);
00423 if (units_ == RADIANS)
00424 two_pi = static_cast<T>(2.0*vnl_math::pi);
00425 for (int el = 0; el<static_cast<int>(n_elevation_); ++el) {
00426 T ec = elevation_center(el);
00427 for (int az = 0; az<static_cast<int>(n_azimuth_); ++az) {
00428 T pc = p(az, el);
00429 if (pc==T(0)) continue;
00430 T ac = azimuth_center(az);
00431 T x, y, z;
00432 convert_to_cartesian(ac, ec, x, y, z);
00433 mean_x += pc*x; mean_y += pc*y; mean_z += pc*z;
00434 }
00435 }
00436 double length = vcl_sqrt(mean_x*mean_x + mean_y*mean_y + mean_z*mean_z);
00437 if (length<1.0e-8)
00438 return vnl_matrix_fixed<T, 2 ,2> ();
00439 mean_x /= length; mean_y /= length; mean_z /= length;
00440 T mean_az, mean_el;
00441 convert_to_spherical(static_cast<T>(mean_x), static_cast<T>(mean_y),
00442 static_cast<T>(mean_z), mean_az, mean_el);
00443 T caz=T(0), caz_el=T(0), cel=T(0);
00444 for (int el = 0; el<static_cast<int>(n_elevation_); ++el) {
00445 T ec = elevation_center(el);
00446 for (int az = 0; az<static_cast<int>(n_azimuth_); ++az)
00447 {
00448 T pc = p(az, el);
00449 if (pc==T(0)) continue;
00450 T ac = azimuth_center(az);
00451 T delta_el = (ec-mean_el);
00452 cel += pc*delta_el*delta_el;
00453 T delta_az = azimuth_diff(mean_az, ac, two_pi);
00454 caz_el += pc*(ec-mean_el)*delta_az;
00455 caz += pc*delta_az*delta_az;
00456 }
00457 }
00458 vnl_matrix_fixed<T, 2, 2> ret;
00459 ret[0][0] = caz; ret[0][1]=caz_el; ret[1][0]=ret[0][1]; ret[1][1]=cel;
00460 return ret;
00461 }
00462
00463 template <class T>
00464 void bsta_spherical_histogram<T>::std_dev(T& std_dev_az, T& std_dev_el)
00465 {
00466 vnl_matrix_fixed<T, 2, 2> covar = covariance_matrix();
00467 double var_az = covar[0][0], var_el = covar[1][1];
00468 std_dev_az = static_cast<T>(vcl_sqrt(var_az));
00469 std_dev_el = static_cast<T>(vcl_sqrt(var_el));
00470 }
00471
00472 template <class T>
00473 vcl_vector<int> bsta_spherical_histogram<T>::
00474 bins_intersecting_cone(T center_az, T center_el, T cone_half_angle)
00475 {
00476 vcl_vector<int> ret;
00477 T xc, yc ,zc;
00478 convert_to_cartesian(center_az, center_el, xc, yc, zc);
00479 vnl_vector<double> cone_axis(3);
00480 cone_axis[0]=xc; cone_axis[1]=yc; cone_axis[2]=zc;
00481 for (int az = 0; az<int(n_azimuth_); ++az)
00482 for (int el = 0; el<int(n_elevation_); ++el) {
00483 T azc = azimuth_center(az), elc = elevation_center(el);
00484 T xb, yb, zb;
00485 convert_to_cartesian(azc, elc, xb, yb, zb);
00486 vnl_vector<double> bin_vector(3);
00487 bin_vector[0]=xb; bin_vector[1]=yb; bin_vector[2]=zb;
00488 double ang = angle(cone_axis, bin_vector);
00489 if (units_ == DEG)
00490 ang = rad_to_deg(static_cast<T>(ang));
00491 if (vcl_fabs(ang)<=cone_half_angle)
00492 ret.push_back(linear_index(az, el));
00493 }
00494 return ret;
00495 }
00496
00497 template <class T>
00498 void bsta_spherical_histogram<T>::
00499 write_counts_with_interval(vcl_ostream& os, int azimuth_index,
00500 int elevation_index) {
00501 T az_start, az_range, el_start, el_range;
00502 int lidx = linear_index(azimuth_index,elevation_index);
00503 T cnts = counts_[lidx];
00504 if (!(cnts>T(0))) return;
00505 azimuth_interval(azimuth_index, az_start, az_range);
00506 elevation_interval(elevation_index, el_start, el_range);
00507 os << "az(s:"<< az_start << " int:" << az_range << "):el(s:"
00508 << el_start << " int:" << el_range << ") "
00509 << cnts <<'\n';
00510 }
00511
00512 template <class T>
00513 void bsta_spherical_histogram<T>::
00514 write_counts_with_center(vcl_ostream& os, int azimuth_index,
00515 int elevation_index) {
00516 int lidx = linear_index(azimuth_index,elevation_index);
00517 T cnts = counts_[lidx];
00518 if (!(cnts>T(0))) return;
00519 T az_center = azimuth_center(azimuth_index);
00520 T el_center = elevation_center(elevation_index);
00521 os << az_center << ' ' << el_center << ' ' << cnts << '\n';
00522 }
00523
00524 template <class T>
00525 void bsta_spherical_histogram<T>::print_to_text(vcl_ostream& os)
00526 {
00527 for (unsigned el = 0; el<n_elevation(); ++el)
00528 for (unsigned az = 0; az<n_azimuth(); ++az)
00529 this->write_counts_with_center(os, az, el);
00530 }
00531
00532 template <class T>
00533 void bsta_spherical_histogram<T>::print_to_vrml(vcl_ostream& os,
00534 T transparency)
00535 {
00536 os << "#VRML V2.0 utf8\n"
00537 << "Background {\n"
00538 << " skyColor [ 0 0 0 ]\n"
00539 << " groundColor [ 0 0 0 ]\n"
00540 << "}\n"
00541 << "PointLight {\n"
00542 << " on FALSE\n"
00543 << " intensity 1\n"
00544 << "ambientIntensity 0\n"
00545 << "color 1 1 1\n"
00546 << "location 0 0 0\n"
00547 << "attenuation 1 0 0\n"
00548 << "radius 100\n"
00549 << "}\n";
00550 for (int az = 0; az<int(n_azimuth_); ++az)
00551 for (int el = 0; el<int(n_elevation_); ++el) {
00552 T cnts = counts(az, el);
00553 if (cnts>0) {
00554 T azc = azimuth_center(az), elc = elevation_center(el);
00555 T x, y, z;
00556 convert_to_cartesian(azc, elc, x, y, z);
00557 os<< "Transform {\n"
00558 << "translation " << x << ' ' << y << ' '
00559 << ' ' << z << '\n'
00560 << "children [\n"
00561 << "Shape {\n"
00562 << " appearance Appearance{\n"
00563 << " material Material\n"
00564 << " {\n"
00565 << " diffuseColor " << 1 << ' ' << 1 << ' ' << 0 << '\n'
00566 << " transparency " << transparency << '\n'
00567 << " }\n"
00568 << " }\n"
00569 << " geometry Sphere\n"
00570 << "{\n"
00571 << " radius " << p(az, el) << '\n'
00572 << " }\n"
00573 << " }\n"
00574 << " ]\n"
00575 << "}\n";
00576 }
00577 }
00578 os << "Transform {\n"
00579 << "translation " << 0 << ' ' << 0 << ' '
00580 << ' ' << 0 << '\n'
00581 << "children [\n"
00582 << "Shape {\n"
00583 << " appearance Appearance{\n"
00584 << " material Material\n"
00585 << " {\n"
00586 << " diffuseColor " << 0 << ' ' << 1 << ' ' << 0 << '\n'
00587 << " transparency " << 0 << '\n'
00588 << " }\n"
00589 << " }\n"
00590 << " geometry Sphere\n"
00591 << "{\n"
00592 << " radius " << 0.95 << '\n'
00593 << " }\n"
00594 << " }\n"
00595 << " ]\n"
00596 << "}\n";
00597 }
00598
00599
00600 template <class T>
00601 vcl_ostream& operator<<(vcl_ostream& s, bsta_spherical_histogram<T> const& h)
00602 {
00603 bsta_spherical_histogram<T>& nch = const_cast<bsta_spherical_histogram<T>&>(h);
00604 s << "bsta_spherical_histogram<T> ==>\n";
00605 if (h.units() == bsta_spherical_histogram<T>::RADIANS)
00606 s << "units: radians\n";
00607 else s << "units: degrees\n";
00608 s << "n_bins_azimuth: " << h.n_azimuth() << " n_bins_elevation: "
00609 << h.n_elevation() << '\n'
00610 << "azimuth(start: " << h.azimuth_start() <<" interval: " << h.azimuth_range()<< " )\n"
00611 << "elevation(start: "<< h.elevation_start()<<" interval: " << h.elevation_range()<<" )\n";
00612 if (h.azimuth_branch_cut() == bsta_spherical_histogram<T>::B_0_360) {
00613 if (h.units() == bsta_spherical_histogram<T>::RADIANS)
00614 s << "azimuth branch cut: 0/2*PI\n";
00615 else
00616 s << "azimuth branch cut: 0/360\n";
00617 }
00618 else {
00619 if (h.units() == bsta_spherical_histogram<T>::RADIANS)
00620 s << "azimuth branch cut: -PI/PI\n";
00621 else
00622 s << "azimuth branch cut: -180/180\n";
00623 }
00624
00625 if (h.elevation_poles() == bsta_spherical_histogram<T>::B_90_90) {
00626 if (h.units()==bsta_spherical_histogram<T>::RADIANS)
00627 s << "south pole: -PI/2 north_pole: PI\n";
00628 else
00629 s << "south pole: -90 north_pole: 90\n";
00630 }
00631 else {
00632 if (h.units()==bsta_spherical_histogram<T>::RADIANS)
00633 s << "south pole: PI north_pole: 0\n";
00634 else
00635 s << "south pole: 180 north_pole: 0\n";
00636 }
00637 s << "-- counts --\n";
00638 for (unsigned r = 0; r<h.n_elevation(); ++r)
00639 for (unsigned c = 0; c<h.n_azimuth(); ++c)
00640 nch.write_counts_with_interval(s, c, r);
00641 return s;
00642 }
00643
00644
00645 template <class T>
00646 vcl_istream& operator>>(vcl_istream& is, bsta_spherical_histogram<T>& h)
00647 {
00648 return is;
00649 }
00650
00651 #undef BSTA_SPHERICAL_HISTOGRAM_INSTANTIATE
00652 #define BSTA_SPHERICAL_HISTOGRAM_INSTANTIATE(T) \
00653 template class bsta_spherical_histogram<T >;\
00654 template vcl_istream& operator>>(vcl_istream&, bsta_spherical_histogram<T >&);\
00655 template vcl_ostream& operator<<(vcl_ostream&, bsta_spherical_histogram<T > const&)
00656
00657 #endif // bsta_spherical_histogram_txx_