Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
VoxelSetIterator.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 // :noTabs=false:tabSize=4:indentSize=4:
4 //
5 // (c) Copyright Rosetta Commons Member Institutions.
6 // (c) This file is part of the Rosetta software suite and is made available under license.
7 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
8 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
9 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
10 
11 /// @file protocols/match/VoxelSetIterator.cc
12 /// @brief Implementation of the VoxelSetIterator class
13 /// @author Alex Zanghellini (zanghell@u.washington.edu)
14 /// @author Andrew Leaver-Fay (aleaverfay@gmail.com), porting to mini
15 
16 // Unit headers
18 
19 // Utility headers
20 #include <utility/FixedSizeLexicographicalIterator.tmpl.hh>
21 
22 // C++ headers
23 
24 namespace protocols {
25 namespace match {
26 
27 using namespace utility;
28 
29 /// @details Initalize the iterator with both the bounding volume and discritezation data
30 /// from the OccupiedSpaceHasher, and also with the coordinates of the 6-d point that this
31 /// instance will be responsible for. One point per VoxelSetIterator.
33  BoundingBox const & bb,
34  Size3 const & n_xyz_bins,
35  Size3 const & n_euler_bins,
36  Real3 const & xyz_bin_widths,
37  Real3 const & euler_bin_widths,
38  Real3 const & xyz_bin_halfwidths,
39  Real3 const & euler_bin_halfwidths,
40  Real6 const & point
41 ) :
42  bb_( bb ),
43  n_xyz_bins_( n_xyz_bins ),
44  n_euler_bins_( n_euler_bins ),
45  xyz_bin_widths_( xyz_bin_widths ),
46  euler_bin_widths_( euler_bin_widths ),
47  xyz_bin_halfwidths_( xyz_bin_halfwidths ),
48  euler_bin_halfwidths_( euler_bin_halfwidths ),
49  point_( point ),
50  //wrap_theta_( false ),
51  theta_near_0_( false ),
52  theta_near_180_( false ),
53  wrapped_phipsi_bins_( 0 ),
54  wrapped_phipsi_halfbins_( 0 ),
55  curr_bin_( 0 ),
56  curr_pos_( 0 )
57 {
58  assert( point_[ 4 ] >= 0 && point_[ 4 ] < 360 );
59  assert( point_[ 5 ] >= 0 && point_[ 5 ] < 360 );
60  assert( point_[ 6 ] >= 0 && point_[ 6 ] <= 180 );
61 
62  /// OK. So we're going to enumerate all 64 voxels that this point will hash into.
63  /// This is made slightly tricky by three facts:
64  /// 1. We might walk outside of the bounding box in the xyz dimensions
65  /// 2. For euler angles "phi" and "psi", the angles are periodic in the range between [ 0 .. 360 ]
66  /// 3. For euler angle "theta" near 180 or 0, we "flip" the "phi" and "psi" angles if phi is greater than 180.
67 
68  for ( Size ii = 1; ii <= 3; ++ii ) {
69  basebin_[ ii ] = static_cast< Size > (( point_[ ii ] - bb_.lower()( ii )) / xyz_bin_widths_[ ii ] );
70  basehalfbin_[ ii ] = static_cast< Size > (( point_[ ii ] - bb_.lower()( ii )) / xyz_bin_halfwidths_[ ii ] ) - 2 * basebin_[ ii ];
71  if ( basebin_[ ii ] >= n_xyz_bins_[ ii ] ) return;
72  }
73  for ( Size ii = 4, ii_minus3 = 1; ii <= 6; ++ii, ++ii_minus3 ) {
74  assert( point_[ ii ] >= 0 && point_[ ii ] <= 360 );
75  assert( ii != 6 || point_[ ii ] <= 180 ); /// theta must range between 0 and 180.
76  basebin_[ ii ] = static_cast< Size > ( point_[ ii ] / euler_bin_widths_[ ii_minus3 ] );
77  basehalfbin_[ ii ] = static_cast< Size > ( point_[ ii ] / euler_bin_halfwidths_[ ii_minus3 ] ) - 2 * basebin_[ ii ];
78 
79  // In floating point, sometimes (360 - epsilon) / X = 360 / X for
80  // values of X that evenly divide 360, and epsilon non-zero. )
81  if ( ii != 6 && basebin_[ ii ] == n_euler_bins_[ ii_minus3 ] ) {
82  basebin_[ ii ] = n_euler_bins_[ ii_minus3 ] - 1;
83  }
84 
85  }
86 
87  fixedsizearray1< Size, 6 > twos( 2 );
88  iter64_.set_dimension_sizes( twos );
89 
90  theta_near_0_ = point_[ 6 ] < euler_bin_halfwidths[ 3 ];
91  theta_near_180_ = point_[ 6 ] > 180 - euler_bin_halfwidths[ 3 ];
92 
93  if ( theta_near_0_ || theta_near_180_ ) {
94  Real wrapped_phi, wrapped_psi;
95  if ( point_[ 4 ] > 180 ) {
96  /// wrap both phi and psi to their negative-rotation values
97  /// when the original phi value is greater than 180; the new
98  /// phi value will be less than 180. The new psi may end up negative, so check if psi - 180 is < 0.
99  wrapped_phi = point_[ 4 ] - 180;
100  wrapped_psi = point_[ 5 ] > 180 ? point_[ 5 ] - 180 : 180 + point_[ 5 ];
101  } else {
102  /// keep phi and psi fixed since phi is < 180 -- let the neighbors > 180 come to us.
103  wrapped_phi = point_[ 4 ];
104  wrapped_psi = point_[ 5 ];
105  }
106  wrapped_phipsi_bins_[ 1 ] = static_cast< Size > (( wrapped_phi ) / euler_bin_widths_[ 1 ] );
107  wrapped_phipsi_bins_[ 2 ] = static_cast< Size > (( wrapped_psi ) / euler_bin_widths_[ 2 ] );
108  wrapped_phipsi_halfbins_[ 1 ] = static_cast< Size > (( wrapped_phi ) / euler_bin_halfwidths_[ 1 ] ) - 2 * wrapped_phipsi_bins_[ 1 ];
109  wrapped_phipsi_halfbins_[ 2 ] = static_cast< Size > (( wrapped_psi ) / euler_bin_halfwidths_[ 2 ] ) - 2 * wrapped_phipsi_bins_[ 2 ];
110  }
112 }
113 
115 {
116  if ( iter64_.at_end() ) return;
117  Size start = 7 - ++iter64_; /// start at the x coordinate if all 6 dimensions rolled over;
118  while ( true ) {
119  if ( iter64_.at_end() ) break;
120 
121  bool outside_bounding_box( false );
122  for ( Size ii = start; ii <= 3; ++ii ) {
123  if ( iter64_[ ii ] == 2 && basebin_[ ii ] == n_xyz_bins_[ ii ] - 1 && basehalfbin_[ ii ] == 1 ) {
124  /// walked out of bounds.
125  start = 7 - iter64_.continue_at_dimension( ii );
126  outside_bounding_box = true;
127  break;
128  }
129  }
130  if ( ! outside_bounding_box ) break;
131  }
132 
133  if ( ! iter64_.at_end() ) calc_bin_and_pos();
134 }
135 
137 {
138  return iter64_.at_end();
139 }
140 
141 void VoxelSetIterator::get_bin_and_pos( Size6 & bin, Size & pos ) const
142 {
143  assert( ! at_end() );
144  bin = curr_bin_;
145  pos = curr_pos_;
146 }
147 
149 {
150  assert( ! at_end() );
151  curr_pos_ = 1; /// curr pos ranges from 1 and 64. The math below will add between 0 and 63 to curr_pos_.
152 
153  for ( Size ii = 1; ii <= 3; ++ii ) {
154  curr_bin_[ ii ] = basebin_[ ii ];
155  if ( iter64_[ ii ] == 2 && basehalfbin_[ ii ] == 1 ) {
156  curr_bin_[ ii ] += 1;
157  } else if ( basehalfbin_[ ii ] == 1 || iter64_[ ii ] == 2 ) {
158  curr_pos_ += ii == 1 ? 32 : ( ii == 2 ? 16 : 8 );
159  }
160  }
161 
162  /// Now handle the Euler bins.
163  /// Two cases:
164  /// 1. Near 0 or Near 360
165  /// 2. Anywhere else
166 
167  if ( ( theta_near_0_ && iter64_[ 6 ] == 1 ) || ( theta_near_180_ && iter64_[ 6 ] == 2 ) ) {
168 
169  // phi and psi
170  for ( Size ii = 4, ii_minus3 = 1; ii <= 5; ++ii, ++ii_minus3 ) {
171  curr_bin_[ ii ] = wrapped_phipsi_bins_[ ii_minus3 ];
172  if ( iter64_[ ii ] == 2 && wrapped_phipsi_halfbins_[ ii_minus3 ] == 1 ) {
173  // increment, and wrap at 360 if necessary
174  curr_bin_[ ii ] = curr_bin_[ ii ] + 1 == n_euler_bins_[ ii_minus3 ] ? 0 : curr_bin_[ ii ] + 1;
175  } else if ( iter64_[ ii ] == 2 || wrapped_phipsi_halfbins_[ ii_minus3 ] == 1 ) {
176  curr_pos_ += ii == 4 ? 4 : 2;
177  }
178  }
179 
180  /// theta
181  if ( theta_near_0_ ) {
182  curr_bin_[ 6 ] = 0;
183  } else {
184  curr_bin_[ 6 ] = n_euler_bins_[ 3 ] - 1;
185  curr_pos_ += 1;
186  }
187  } else {
188  for ( Size ii = 4, ii_minus3 = 1; ii <= 6; ++ii, ++ii_minus3 ) {
189  curr_bin_[ ii ] = basebin_[ ii ];
190  if ( iter64_[ ii ] == 2 && basehalfbin_[ ii ] == 1 ) {
191  // Wrap at > 360 -- only applies to phi and psi, but we've gotten to this point knowing
192  // that the above condition does not apply to theta, so no need for an ii==4 || ii==5 check.
193  assert( ii != 6 || curr_bin_[ ii ] + 1 != n_euler_bins_[ ii_minus3 ] );
194  curr_bin_[ ii ] = ( curr_bin_[ ii ] + 1 == n_euler_bins_[ ii_minus3 ] ? 0 : curr_bin_[ ii ] + 1 );
195  } else if ( basehalfbin_[ ii ] == 1 || iter64_[ ii ] == 2 ) {
196  curr_pos_ += ii == 4 ? 4 : ( ii == 5 ? 2 : 1 );
197  }
198  }
199  }
200 }
201 
202 }
203 }