File indexing completed on 2026-04-09 07:48:58
0001 #include "SLOG.hh"
0002 #include "SSys.hh"
0003 #include "SPath.hh"
0004 #include "sc4u.h"
0005
0006 #include "CSGFoundry.h"
0007 #include "SName.h"
0008 #include "CSGQuery.h"
0009 #include "CSGGrid.h"
0010
0011 #ifdef DEBUG_RECORD
0012 #include "CSGRecord.h"
0013 #endif
0014
0015 #ifdef DEBUG_CYLINDER
0016 #include "CSGDebug_Cylinder.hh"
0017 #endif
0018
0019
0020 #include "OpticksCSG.h"
0021
0022
0023
0024 #include "csg_intersect_leaf.h"
0025 #include "csg_intersect_node.h"
0026 #include "csg_intersect_tree.h"
0027
0028
0029 const plog::Severity CSGQuery::LEVEL = SLOG::EnvLevel("CSGQuery", "DEBUG") ;
0030
0031 const int CSGQuery::VERBOSE = SSys::getenvint("VERBOSE", 0);
0032
0033
0034 CSGQuery::CSGQuery( const CSGFoundry* fd_ )
0035 :
0036 fd(fd_),
0037 prim0(fd->getPrim(0)),
0038 node0(fd->getNode(0)),
0039 plan0(fd->getPlan(0)),
0040 itra0(fd->getItra(0)),
0041 select_prim(nullptr),
0042 select_nodeOffset(0),
0043 select_prim_numNode(0),
0044 select_root_node(nullptr),
0045 select_root_typecode(CSG_ZERO),
0046 select_root_subNum(0),
0047 select_is_tree(true)
0048 {
0049 init();
0050 }
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 void CSGQuery::init()
0065 {
0066
0067 int solidIdx = 0 ;
0068 int primIdxRel = 0 ;
0069
0070 const char* sopr = SSys::getenvvar("SOPR", "0:0" );
0071 SName::ParseSOPR(solidIdx, primIdxRel, sopr );
0072
0073 LOG(LEVEL) << " sopr " << sopr << " solidIdx " << solidIdx << " primIdxRel " << primIdxRel ;
0074 selectPrim(solidIdx, primIdxRel );
0075 }
0076
0077 void CSGQuery::selectPrim(unsigned solidIdx, unsigned primIdxRel )
0078 {
0079 const CSGPrim* pr = fd->getSolidPrim(solidIdx, primIdxRel);
0080 assert( pr );
0081 selectPrim(pr);
0082 }
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094 void CSGQuery::selectPrim( const CSGPrim* pr )
0095 {
0096 select_prim = pr ;
0097 select_prim_ce = pr->ce();
0098 select_nodeOffset = pr->nodeOffset() ;
0099 select_prim_numNode = pr->numNode() ;
0100 select_root_node = node0 + pr->nodeOffset() ;
0101 select_root_typecode = select_root_node->typecode();
0102 select_root_subNum = select_root_node->subNum();
0103
0104
0105
0106 select_is_tree = CSG::IsTree((OpticksCSG_t)select_root_typecode) ;
0107
0108 LOG_IF(info, VERBOSE > 0)
0109 << " select_prim " << select_prim
0110 << " select_nodeOffset " << select_nodeOffset
0111 << " select_prim_numNode " << select_prim_numNode
0112 << " select_root_node " << select_root_node
0113 << " select_root_typecode " << CSG::Name(select_root_typecode)
0114 << " select_root_subNum " << select_root_subNum
0115 << " getSelectedTreeHeight " << getSelectedTreeHeight()
0116 ;
0117
0118 LOG_IF(LEVEL, select_root_subNum == 0) << "select_root_subNum ZERO " ;
0119
0120 }
0121
0122 int CSGQuery::getSelectedType() const
0123 {
0124 return select_root_typecode ;
0125 }
0126 int CSGQuery::getSelectedTreeHeight() const
0127 {
0128 return select_is_tree ? TREE_HEIGHT(select_root_subNum) : -1 ;
0129 }
0130
0131
0132
0133
0134
0135
0136
0137 const CSGNode* CSGQuery::getSelectedNode( int nodeIdx ) const
0138 {
0139 const CSGNode* nd = nodeIdx < select_prim_numNode ? select_root_node + nodeIdx : nullptr ;
0140 return nd ;
0141 }
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153 const CSGNode* CSGQuery::getSelectedTreeNode( int nodeIdx ) const
0154 {
0155 const CSGNode* nd = nodeIdx < select_root_subNum ? select_root_node + nodeIdx : nullptr ;
0156 return nd ;
0157 }
0158
0159
0160 float CSGQuery::distance(const float3& position ) const
0161 {
0162 float sd = distance_prim( position, select_root_node, plan0, itra0 ) ;
0163 return sd ;
0164 }
0165
0166 float CSGQuery::operator()(const float3& position ) const
0167 {
0168 return distance(position);
0169 }
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180 bool CSGQuery::intersect( quad4& isect, float t_min, const quad4& p ) const
0181 {
0182
0183 float3 ray_origin = make_float3( p.q0.f.x, p.q0.f.y, p.q0.f.z );
0184 float3 ray_direction = make_float3( p.q1.f.x, p.q1.f.y, p.q1.f.z );
0185 unsigned gsid = p.q3.u.w ;
0186 return intersect( isect, t_min, ray_origin, ray_direction, gsid );
0187 }
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231 bool CSGQuery::intersect( quad4& isect, float t_min, const float3& ray_origin, const float3& ray_direction, unsigned gsid ) const
0232 {
0233 isect.zero();
0234
0235 isect.q2.f.x = ray_origin.x ;
0236 isect.q2.f.y = ray_origin.y ;
0237 isect.q2.f.z = ray_origin.z ;
0238 isect.q2.f.w = t_min ;
0239
0240 isect.q3.f.x = ray_direction.x ;
0241 isect.q3.f.y = ray_direction.y ;
0242 isect.q3.f.z = ray_direction.z ;
0243 isect.q3.u.w = gsid ;
0244
0245 #ifdef DEBUG
0246 std::cout << "CSGQuery::intersect ray_origin " << ray_origin << " ray_direction " << ray_direction << std::endl ;
0247 #endif
0248
0249 bool dump = false ;
0250 bool valid_intersect = intersect_prim( isect.q0.f, select_root_node, plan0, itra0, t_min, ray_origin, ray_direction, dump ) ;
0251 if( valid_intersect )
0252 {
0253 float t = isect.q0.f.w ;
0254 float3 ipos = ray_origin + t*ray_direction ;
0255
0256 float sd = distance(ipos) ;
0257
0258 isect.q1.f.x = ipos.x ;
0259 isect.q1.f.y = ipos.y ;
0260 isect.q1.f.z = ipos.z ;
0261 isect.q1.f.w = sd ;
0262 }
0263 return valid_intersect ;
0264 }
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279 void CSGQuery::distance( quad4& isect, const float3& ray_origin ) const
0280 {
0281 isect.zero();
0282 isect.q1.f.w = distance(ray_origin) ;
0283
0284 isect.q2.f.x = ray_origin.x ;
0285 isect.q2.f.y = ray_origin.y ;
0286 isect.q2.f.z = ray_origin.z ;
0287 isect.q2.f.w = 0.f ;
0288 }
0289
0290
0291 const float CSGQuery::SD_CUT = -1e-3 ;
0292
0293 bool CSGQuery::IsSpurious( const quad4& isect )
0294 {
0295 float sd = isect.q1.f.w ;
0296 bool spurious = sd < SD_CUT ;
0297 return spurious ;
0298 }
0299
0300
0301 std::string CSGQuery::Label()
0302 {
0303 std::stringstream ss ;
0304 ss << "CSGQuery::Label " ;
0305
0306 #ifdef DEBUG
0307 ss << " DEBUG" ;
0308 #else
0309 ss << " not-DEBUG" ;
0310 #endif
0311
0312 #ifdef DEBUG_RECORD
0313 ss << " DEBUG_RECORD" ;
0314 #else
0315 ss << " not-DEBUG_RECORD" ;
0316 #endif
0317
0318 #ifdef DEBUG_CYLINDER
0319 ss << " DEBUG_CYLINDER" ;
0320 #else
0321 ss << " not-DEBUG_CYLINDER" ;
0322 #endif
0323
0324
0325
0326 std::string s = ss.str() ;
0327 return s ;
0328 }
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338 std::string CSGQuery::Desc( const quad4& isect, const char* label, bool* valid_intersect )
0339 {
0340 float sd = isect.q1.f.w ;
0341 bool spurious = IsSpurious(isect);
0342 std::stringstream ss ;
0343 ss
0344 << std::setw(30) << label
0345 << " "
0346 << ( valid_intersect ? ( *valid_intersect ? "HIT" : "MISS" ) : " " )
0347 << std::endl
0348 << std::setw(30) << " q0 norm t "
0349 << "("
0350 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q0.f.x
0351 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q0.f.y
0352 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q0.f.z
0353 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q0.f.w
0354 << ")"
0355 << std::endl
0356 << std::setw(30) << " q1 ipos sd "
0357 << "("
0358 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q1.f.x
0359 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q1.f.y
0360 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q1.f.z
0361 << std::setw(10) << std::fixed << std::setprecision(4) << sd
0362 << ")"
0363 << ( spurious ? " SPURIOUS INTERSECT " : "-" )
0364 << " sd < SD_CUT : "
0365 << std::setw(10) << std::fixed << std::setprecision(4) << SD_CUT
0366 << std::endl
0367 << std::setw(30) << " q2 ray_ori t_min "
0368 << "("
0369 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q2.f.x
0370 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q2.f.y
0371 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q2.f.z
0372
0373 << ")"
0374 << std::endl
0375 << std::setw(30) << " q3 ray_dir gsid "
0376 << "("
0377 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q3.f.x
0378 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q3.f.y
0379 << std::setw(10) << std::fixed << std::setprecision(4) << isect.q3.f.z
0380 << std::setw(20) << C4U_desc(isect.q3.u.w)
0381 << ")"
0382 << std::endl
0383 ;
0384
0385 std::string s = ss.str() ;
0386 return s ;
0387 }
0388
0389
0390
0391
0392
0393
0394
0395 bool CSGQuery::simtrace( quad4& p ) const
0396 {
0397 float3* ray_origin = p.v2() ;
0398 float3* ray_direction = p.v3() ;
0399 float t_min = p.q1.f.w ;
0400
0401
0402 bool dump = false ;
0403 bool valid_intersect = intersect_prim( p.q0.f, select_root_node, plan0, itra0, t_min, *ray_origin, *ray_direction, dump ) ;
0404 if( valid_intersect )
0405 {
0406 float t = p.q0.f.w ;
0407 float3 ipos = (*ray_origin) + t*(*ray_direction) ;
0408 p.q1.f.x = ipos.x ;
0409 p.q1.f.y = ipos.y ;
0410 p.q1.f.z = ipos.z ;
0411
0412 }
0413 return valid_intersect ;
0414 }
0415
0416
0417 void CSGQuery::post(const char* outdir)
0418 {
0419 #ifdef DEBUG_CYLINDER
0420 if(outdir)
0421 {
0422 const std::vector<CSGDebug_Cylinder>& record = CSGDebug_Cylinder::record ;
0423 LOG(info) << " CSGDebug_Cylinder::record.size " << record.size() << " outdir " << outdir ;
0424 CSGDebug_Cylinder::Save(outdir);
0425 }
0426 #endif
0427 }
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437 bool CSGQuery::intersect_again( quad4& isect, const quad4& prev ) const
0438 {
0439 float3* ray_origin = prev.v2() ;
0440 float3* ray_direction = prev.v3() ;
0441 float t_min = prev.q1.f.w ;
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456 unsigned gsid = prev.q3.u.w ;
0457
0458 #ifdef DEBUG_RECORD
0459 CSGRecord::SetEnabled(true);
0460 #endif
0461
0462 bool valid_intersect = intersect( isect, t_min, *ray_origin, *ray_direction, gsid );
0463
0464 #ifdef DEBUG_RECORD
0465 CSGRecord::SetEnabled(false);
0466 #endif
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477 return valid_intersect ;
0478 }
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489 CSGGrid* CSGQuery::scanPrim(int resolution) const
0490 {
0491 const CSGPrim* pr = select_prim ;
0492 if( pr == nullptr )
0493 {
0494 LOG(fatal) << " no prim is selected " ;
0495 return nullptr ;
0496 }
0497
0498 const float4 ce = pr->ce() ;
0499 LOG(info) << " ce " << ce << " resolution " << resolution ;
0500
0501 CSGGrid* grid = new CSGGrid( ce, resolution, resolution, resolution );
0502 grid->scan(*this) ;
0503 return grid ;
0504 }
0505
0506
0507
0508 std::string CSGQuery::descPrim() const
0509 {
0510 std::stringstream ss ;
0511 for(int nodeIdx=select_nodeOffset ; nodeIdx < select_nodeOffset+select_prim_numNode ; nodeIdx++)
0512 {
0513 const CSGNode* nd = node0 + nodeIdx ;
0514 ss << nd->desc() << std::endl ;
0515 }
0516 std::string s = ss.str();
0517 return s ;
0518 }
0519
0520
0521 void CSGQuery::dumpPrim(const char* msg) const
0522 {
0523 if( select_prim_numNode == 0 ) return ;
0524 LOG(LEVEL)
0525 << msg
0526 << " select_prim_numNode " << select_prim_numNode
0527 << " select_nodeOffset " << select_nodeOffset
0528 << std::endl
0529 << descPrim()
0530 ;
0531
0532 }
0533
0534 void CSGQuery::dump(const char* msg) const
0535 {
0536 LOG(info) << msg ;
0537 dumpPrim();
0538 }
0539
0540