00001
00002
00003
00004
00005 #include "geometry/Volume.h"
00006 #include "geometry/Ray.h"
00007 #include "geometry/Intersection.h"
00008 #include <cassert>
00009 # include <strstream>
00010
00011 static unsigned s_count=0;
00012
00013 const double Volume::Surface_EPSILON= 2e-5;
00014
00015 Volume::Volume(unsigned n)
00016 : SurfaceList(n)
00017 , max_dimension(FLT_MAX)
00018 {
00019 s_count=0;
00020 }
00021
00022 void Volume::addSurface(Surface* s)
00023 {
00024 if( s_count<size() )
00025 operator[](s_count++)=s;
00026 else {
00027 push_back(s);
00028 s_count++;
00029 }
00030 }
00031
00032 Volume::~Volume()
00033 {
00034 deleteSurfaces();
00035 }
00036
00037 void Volume::deleteSurfaces()
00038 {
00039 for( iterator it=begin(); it !=end(); ++it) {
00040 delete *it; *it = 0;
00041 }
00042 s_count=0;
00043 }
00044
00045 GeomObject&
00046 Volume::transform(const CoordTransform& T)
00047 {
00048 Shape::transform(T);
00049 for(unsigned i=0; i<surfaceCount(); i++)
00050 surface(i).transform(T);
00051 return *this;
00052 }
00053
00054 void Volume::printOn( std::ostream& os ) const
00055 {
00056 Shape::printOn(os);
00057 os << " maximum dimension " << max_dimension << "\n"
00058 << "bounded by the surfaces:\n";
00059 for(unsigned i=0; i<surfaceCount(); i++)
00060 os << surface(i);
00061 }
00062
00063 static unsigned isurf;
00064 int
00065 Volume::getBoundaryIndex(const Point& p)const
00066 {
00067 double closest = FLT_MAX;
00068 int found = -1;
00069 for( const_iterator it=begin(); it!=end(); ++it) {
00070 double d = fabs( (*it)->how_near(p) );
00071 if( d < closest ) {
00072 found = it-begin();
00073 closest = d;
00074 }
00075 }
00076 if( closest< Surface_EPSILON)
00077 return found;
00078 WARNING("Volume::associate: suface to tag not found");
00079 return -1;
00080 }
00081 int
00082 Volume::lastBoundaryIndex()const
00083 {
00084
00085
00086 return isurf;
00087 }
00088
00089 enum Surface_Status {Surface_INSIDE, Surface_AMBIGOUS, Surface_OUTSIDE} ;
00090
00091
00092
00093
00094
00095
00096
00097 enum Surface_Solution {Surface_SOLUTION, Surface_UNREACHABLE, Surface_NO_SOLUTION} ;
00098
00099
00100
00101
00102
00103
00104
00105 static double Surface_distanceToLeave( const Surface &s, const Ray& r, double maxStep, Surface_Status& status, Surface_Solution& solution )
00106 {
00107 double d = s.how_near( r.position() );
00108
00109 if ( d > maxStep ) {
00110
00111
00112 status = Surface_INSIDE;
00113 solution = Surface_UNREACHABLE;
00114 return maxStep;
00115 }
00116
00117
00118 if ( d < -Volume::Surface_EPSILON ) {
00119
00120 std::ostrstream error_text;
00121 error_text << "Volume--bad geometry for surface \n\t" << s
00122 << "\n\t" << r.position() << " is " << d << "cm outside\n";
00123 error_text << '\0';
00124 WARNING(error_text.str());
00125 status = Surface_OUTSIDE;
00126 solution = Surface_NO_SOLUTION;
00127 return FLT_MAX;
00128 }
00129 else if (d < Volume::Surface_EPSILON ) {
00130
00131
00132 status = Surface_AMBIGOUS;
00133 solution = Surface_SOLUTION;
00134
00135 #if 0 // THB: this screws me up
00136 if (s.normal( r.position() ) * r.direction() > 0)
00137 return 0;
00138 #endif
00139
00140 Intersection inter(r,s);
00141 d = inter.distance(maxStep, 1);
00142
00143 solution = (d == FLT_MAX) ? Surface_NO_SOLUTION : Surface_SOLUTION;
00144 return d;
00145 }
00146 else {
00147
00148
00149 status = Surface_INSIDE;
00150
00151 Intersection inter(r,s);
00152 d = inter.distance(maxStep, 1);
00153
00154 solution = (d == FLT_MAX) ? Surface_NO_SOLUTION : Surface_SOLUTION;
00155 return d;
00156 }
00157 }
00158
00159
00160 double
00161 Volume::distanceToLeave( const Ray& r, double maxStep ) const
00162 {
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 double t = FLT_MAX;
00179 Surface_Status statusVolume = Surface_INSIDE;
00180 Surface_Solution solutionVolume = Surface_NO_SOLUTION;
00181
00182 isurf = 99999;
00183 for (unsigned i=0; i< surfaceCount(); i++) {
00184 const Surface& s = surface(i);
00185 Surface_Status status;
00186 Surface_Solution solution;
00187 double d = Surface_distanceToLeave( s, r, maxStep, status, solution );
00188
00189 if ( status == Surface_OUTSIDE )
00190 {
00191 statusVolume = Surface_OUTSIDE;
00192 solutionVolume = Surface_NO_SOLUTION;
00193 return FLT_MAX;
00194 }
00195
00196
00197
00198
00199
00200 if (t == 0)
00201 {
00202 statusVolume = Surface_AMBIGOUS;
00203 solutionVolume = Surface_SOLUTION;
00204 return 0;
00205 }
00206
00207 if ( status > statusVolume )
00208 statusVolume = status;
00209
00210 if ( solution < solutionVolume )
00211 solutionVolume = solution;
00212
00213 if (d < t)
00214 {
00215 isurf = i;
00216 t = d;
00217 }
00218 }
00219
00220
00221
00222
00223
00224
00225
00226
00227 if (solutionVolume == Surface_UNREACHABLE)
00228
00229
00230 return t;
00231
00232 if (solutionVolume == Surface_NO_SOLUTION) {
00233
00234 #if 0 // do not need anymore? def _DEBUG
00235 std::cerr << "Volume::distanceToLeave, can't leave!\n";
00236 std::cerr << "\tVolume=" << *this << '\n';
00237 std::cerr << "\tRay= " << r << '\n';
00238 #endif
00239 return FLT_MAX;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 Point p = r.position(t);
00259 int bad=0;
00260 for (unsigned j=0; j<surfaceCount(); j++)
00261 {
00262 if (j==isurf)
00263 continue;
00264
00265 bad = (surface(j).how_near(p) < -Surface_EPSILON);
00266
00267 if ( bad )
00268 {
00269 std::ostrstream cerr;
00270 cerr << "Volume::distanceToLeave, position bad by "
00271 << surface(j).how_near(p) << '\n';
00272 cerr << "\tVolume=" << *this << '\n';
00273 cerr << "\tRay= " << r << '\n';
00274 cerr << "\tPoint" << p << '\n';
00275 cerr << '\0'; WARNING(cerr.str());
00276 solutionVolume = Surface_NO_SOLUTION;
00277 return FLT_MAX;
00278 }
00279 }
00280
00281 return t;
00282 }
00283
00284
00285 double
00286 Volume::distanceToEnter( const Ray& r, double maxStep ) const
00287 {
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 Point startPos = r.position();
00298
00299 if( maxStep < FLT_MAX ) {
00300 Vector oc = center() - startPos;
00301 if ( ( oc.mag() - max_dimension ) > maxStep ) return FLT_MAX;
00302 }
00303
00304 double t = FLT_MAX;
00305
00306 for(unsigned i=0; i<surfaceCount(); i++) {
00307
00308
00309
00310 double d = surface(i).how_near(startPos);
00311 if( d> Surface_EPSILON
00312 || fabs(d) > t
00313 || fabs(d) > maxStep
00314 ) continue;
00315
00316
00317 Intersection inter(r,surface(i));
00318 d = inter.distance(maxStep, -1 );
00319 if( d< 0 && d > -Surface_EPSILON)
00320 d=0;
00321
00322 if( d < t && d >= 0 ){
00323
00324
00325 Point p = r.position(d);
00326 int bad=0;
00327 for(unsigned j=0; j<surfaceCount(); j++) {
00328 if(j==i) continue;
00329 if( (bad = !surface(j).inside(p))!=0)break;
00330 }
00331 if( !bad ) {
00332 t = d;
00333 break;
00334 }
00335 }
00336 }
00337 return t;
00338 }
00339
00340 int
00341 Volume::inside( const Point& x ) const
00342 {
00343
00344
00345
00346
00347 for(unsigned i=0; i<surfaceCount(); i++)
00348 {
00349 if( !surface(i).inside( x ))
00350 return 0;
00351 }
00352 return 1;
00353 }
00354