Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:48:55

0001 
0002 #include <csignal>
0003 #include "scuda.h"
0004 #include "sqat4.h"
0005 #include "ssys.h"
0006 
0007 #ifdef WITH_S_BB
0008 #include "s_bb.h"
0009 #else
0010 #include "saabb.h"
0011 #endif
0012 
0013 #include "SLOG.hh"
0014 
0015 #include "SBitSet.h"
0016 #include "OpticksCSG.h"
0017 
0018 #include "CSGFoundry.h"
0019 #include "CSGSolid.h"
0020 #include "CSGPrim.h"
0021 #include "CSGNode.h"
0022 
0023 #include "CSGCopy.h"
0024 
0025 
0026 const plog::Severity CSGCopy::LEVEL = SLOG::EnvLevel("CSGCopy", "DEBUG" ); 
0027 const int CSGCopy::DUMP_RIDX = ssys::getenvint("DUMP_RIDX", -1) ; 
0028 const int CSGCopy::DUMP_NPS = ssys::getenvint("DUMP_NPS", 0) ; 
0029 
0030 
0031 
0032 CSGFoundry* CSGCopy::Clone(const CSGFoundry* src )
0033 {
0034     CSGCopy cpy(src, nullptr); 
0035     cpy.copy(); 
0036     LOG(info) << cpy.desc(); 
0037     return cpy.dst ; 
0038 }
0039 
0040 /**
0041 CSGCopy::Select
0042 ------------------
0043 
0044 Used from CSGFoundry::CopySelect 
0045 
0046 Q: How to detect a "no-selection" SBitSet ? 
0047 A: SBitSet::is_all_set indicates all bits are set, hence no selection
0048 
0049 **/
0050 
0051 CSGFoundry* CSGCopy::Select(const CSGFoundry* src, const SBitSet* elv )
0052 {
0053     CSGCopy cpy(src, elv); 
0054     cpy.copy(); 
0055     LOG(LEVEL) << cpy.desc(); 
0056     return cpy.dst ; 
0057 }
0058 
0059 CSGCopy::CSGCopy(const CSGFoundry* src_, const SBitSet* elv_)
0060     :
0061     src(src_),
0062     sNumSolid(src->getNumSolid()),
0063     solidMap(new int[sNumSolid]), 
0064     sSolidIdx(~0u), 
0065     elv(elv_),
0066     identical(elv ? elv->is_all_set() : true),
0067     identical_bbox_cheat(identical && true),
0068     dst(new CSGFoundry)
0069 {
0070 }
0071 
0072 std::string CSGCopy::desc() const 
0073 {
0074     std::stringstream ss ; 
0075     ss 
0076         << std::endl 
0077         << "src:" 
0078         << src->desc() 
0079         << std::endl 
0080         << "dst:" 
0081         << dst->desc()
0082         << std::endl 
0083         ; 
0084     std::string s = ss.str(); 
0085     return s ; 
0086 }
0087 
0088 CSGCopy::~CSGCopy()
0089 {
0090     delete [] solidMap ; 
0091 }
0092 
0093 unsigned CSGCopy::Dump( unsigned sSolidIdx )
0094 {
0095     return ( DUMP_RIDX >= 0 && unsigned(DUMP_RIDX) == sSolidIdx ) ? DUMP_NPS : 0u ; 
0096 }
0097 
0098 /**
0099 CSGCopy::copy
0100 --------------
0101 
0102 The point of cloning is to provide an easily verifiable starting point 
0103 to implementing Prim selection so must not descend to very low level cloning.
0104 
0105 * this has some similarities with CSGFoundry::addDeepCopySolid and CSG_GGeo/CSG_GGeo_Convert.cc
0106 
0107 * Blind copying makes no sense as offsets will be different with selection  
0108   only some metadata referring back to the GGeo geometry is appropriate for copying
0109 
0110 * When selecting numPrim will sometimes be less in dst, sometimes even zero, 
0111   so need to count selected Prim before adding the solid.
0112 
0113 * ALSO selections can change the number of solids 
0114 
0115 **/
0116 
0117 void CSGCopy::copy()
0118 { 
0119     CSGFoundry::CopyNames(dst, src );  
0120     // No accounting for selection changing the number of names
0121     // as these are LV level names. The LV idx are regarded as 
0122     // external and unchanged no matter the selection, unlike gas_idx. 
0123  
0124     for(unsigned i=0 ; i < sNumSolid ; i++)
0125     {
0126         sSolidIdx = i ; 
0127         solidMap[sSolidIdx] = -1 ; 
0128 
0129         unsigned dump_ = Dump(sSolidIdx); 
0130         bool dump_solid = dump_ & 0x1 ; 
0131         LOG_IF(info, dump_solid) 
0132             << "sSolidIdx " << sSolidIdx 
0133             << " DUMP_RIDX " << DUMP_RIDX  
0134             << " DUMP_NPS " << DUMP_NPS 
0135             << " dump_solid " << dump_solid  
0136             ;   
0137 
0138         const CSGSolid* sso = src->getSolid(sSolidIdx);
0139         unsigned numSelectedPrim = src->getNumSelectedPrimInSolid(sso, elv );  
0140         const std::string& solidMMLabel = src->getSolidMMLabel(sSolidIdx); 
0141 
0142         char sIntent = sso->getIntent(); 
0143 
0144         LOG(LEVEL) 
0145             << " sSolidIdx/sNumSolid/numSelectedPrim"
0146             << std::setw(2) << sSolidIdx 
0147             << "/" 
0148             << std::setw(2) << sNumSolid 
0149             << "/" 
0150             << std::setw(4) << numSelectedPrim 
0151             << " [" << sIntent << "] "
0152             << ": "
0153             << solidMMLabel
0154             ;
0155 
0156         LOG_IF(LEVEL, dump_solid) << " sso " << sso->desc() << " numSelectedPrim " << numSelectedPrim << " solidMMLabel " << solidMMLabel ; 
0157 
0158         if( numSelectedPrim == 0 ) continue ;  
0159 
0160         dst->addSolidMMLabel( solidMMLabel.c_str() );  
0161 
0162         unsigned dSolidIdx = dst->getNumSolid() ; // index before adding (0-based)
0163         if( elv == nullptr ) assert( dSolidIdx == sSolidIdx ); 
0164 
0165         CSGSolid* dso = dst->addSolid(numSelectedPrim, sso->label );   
0166         int dPrimOffset = dso->primOffset ;       
0167         assert( dPrimOffset == int(dst->prim.size()) );  
0168 
0169         CSGSolid::CopyIntent( dso, sso ); 
0170 
0171 
0172 
0173         solidMap[sSolidIdx] = dSolidIdx ; 
0174 
0175 #ifdef WITH_S_BB
0176         s_bb solid_bb = {} ; 
0177 #else
0178         AABB solid_bb = {} ;
0179 #endif
0180 
0181         copySolidPrim(solid_bb, dPrimOffset, sso);  
0182 
0183         unsigned numSelectedPrimCheck = dst->prim.size() - dPrimOffset ; 
0184         bool numSelectedPrim_expect = numSelectedPrim == numSelectedPrimCheck ;
0185         assert( numSelectedPrim_expect );  
0186         if(!numSelectedPrim_expect) std::raise(SIGINT); 
0187 
0188         if(identical_bbox_cheat) // only admissable when no selection 
0189         { 
0190             dso->center_extent = sso->center_extent ;  
0191         }
0192         else
0193         {
0194 #ifdef WITH_S_BB
0195             float* ce = &(dso->center_extent.x) ; 
0196             solid_bb.center_extent( ce ) ;  
0197 #else
0198             dso->center_extent = solid_bb.center_extent(); 
0199 #endif
0200         }
0201 
0202         LOG_IF(LEVEL, dump_solid) << " dso " << dso->desc() ; 
0203 
0204     }   // over solids of the entire geometry 
0205 
0206     copySolidInstances(); 
0207 }
0208 
0209 
0210 
0211 
0212 
0213 /**
0214 CSGCopy::copySolidPrim
0215 ------------------------
0216 
0217 See the AABB mechanics at the tail of CSGFoundry::addDeepCopySolid
0218 
0219 **/
0220 
0221 #ifdef WITH_S_BB
0222 void CSGCopy::copySolidPrim(s_bb& solid_bb, int dPrimOffset, const CSGSolid* sso )
0223 #else
0224 void CSGCopy::copySolidPrim(AABB& solid_bb, int dPrimOffset, const CSGSolid* sso )
0225 #endif
0226 {
0227     unsigned dump_ = Dump(sSolidIdx); 
0228     bool dump_prim = ( dump_ & 0x2 ) != 0u ; 
0229 
0230     for(int primIdx=sso->primOffset ; primIdx < sso->primOffset+sso->numPrim ; primIdx++)
0231     {
0232          const CSGPrim* spr = src->getPrim(primIdx); 
0233          unsigned meshIdx = spr->meshIdx() ; 
0234          unsigned repeatIdx = spr->repeatIdx() ; 
0235          bool selected = elv == nullptr ? true : elv->is_set(meshIdx) ; 
0236          if( selected == false ) continue ; 
0237 
0238          unsigned numNode = spr->numNode()  ;  // not envisaging node selection, so this will be same in src and dst 
0239          unsigned dPrimIdx_global = dst->getNumPrim() ;            // destination numPrim prior to prim addition
0240          unsigned dPrimIdx_local = dPrimIdx_global - dPrimOffset ; // make the PrimIdx local to the solid 
0241 
0242          CSGPrim* dpr = dst->addPrim(numNode, -1 ); 
0243          if( identical ) assert( dpr->nodeOffset() == spr->nodeOffset() ); 
0244 
0245          dpr->setMeshIdx(meshIdx);    
0246          dpr->setRepeatIdx(repeatIdx); 
0247          dpr->setPrimIdx(dPrimIdx_local); 
0248 
0249 #ifdef WITH_S_BB
0250          s_bb prim_bb = {} ;
0251 #else
0252          AABB prim_bb = {} ;
0253 #endif
0254          copyPrimNodes(prim_bb, spr ); 
0255 
0256          if(identical_bbox_cheat)  // only admissable when no selection
0257          {
0258              dpr->setAABB( spr->AABB() );
0259          }
0260          else
0261          {
0262 #ifdef WITH_S_BB
0263              prim_bb.write<float>( dpr->AABB_() ); 
0264 #else
0265              dpr->setAABB( prim_bb.data() ); 
0266 #endif
0267          } 
0268 
0269          unsigned mismatch = 0 ; 
0270          std::string cf = AABB::Compare(mismatch, spr->AABB(), dpr->AABB(), 1, 1e-6 ) ; 
0271          if ( dump_prim && mismatch > 0 )
0272          {
0273              std::cout << std::endl ;  
0274              std::cout << "spr " << spr->desc() << std::endl ; 
0275              std::cout << "dpr " << dpr->desc() << std::endl ; 
0276              std::cout << "prim_bb " << std::setw(20) << " " << prim_bb.desc() << std::endl ; 
0277              std::cout << " AABB::Compare " << cf << std::endl ; 
0278          }
0279 
0280          solid_bb.include_aabb(prim_bb.data()); 
0281     }   // over prim of the solid
0282 }
0283 
0284 
0285 /**
0286 CSGCopy::copyPrimNodes
0287 -------------------------
0288 
0289 **/
0290 
0291 #ifdef WITH_S_BB
0292 void CSGCopy::copyPrimNodes(s_bb& prim_bb, const CSGPrim* spr )
0293 #else
0294 void CSGCopy::copyPrimNodes(AABB& prim_bb, const CSGPrim* spr )
0295 #endif
0296 {
0297     for(int nodeIdx=spr->nodeOffset() ; nodeIdx < spr->nodeOffset()+spr->numNode() ; nodeIdx++)
0298     {
0299         copyNode( prim_bb, nodeIdx ); 
0300     }   
0301 }
0302 
0303 /**
0304 CSGCopy::copyNode
0305 --------------------
0306 
0307 see tail of CSG_GGeo_Convert::convertNode which uses qat4::transform_aabb_inplace to change CSGNode aabb
0308 also see tail of CSGFoundry::addDeepCopySolid
0309 
0310 **/
0311 
0312 #ifdef WITH_S_BB
0313 void CSGCopy::copyNode(s_bb& prim_bb, unsigned nodeIdx )
0314 #else
0315 void CSGCopy::copyNode(AABB& prim_bb, unsigned nodeIdx )
0316 #endif
0317 {
0318     unsigned dump_ = Dump(sSolidIdx); 
0319     bool dump_node = ( dump_ & 0x4 ) != 0u ; 
0320 
0321     const CSGNode* snd = src->getNode(nodeIdx); 
0322     unsigned stypecode = snd->typecode(); 
0323     unsigned sTranIdx = snd->gtransformIdx(); 
0324     bool complement = snd->is_complement();  
0325     bool has_planes = CSG::HasPlanes(stypecode) ; 
0326     bool has_transform = sTranIdx > 0u ; 
0327 
0328     std::vector<float4> splanes ; 
0329     src->getNodePlanes(splanes, snd); 
0330 
0331     unsigned dTranIdx = 0u ; 
0332     const qat4* tra = nullptr ; 
0333     const qat4* itr = nullptr ; 
0334 
0335     if(has_transform)
0336     {
0337         tra = src->getTran(sTranIdx-1u) ; 
0338         itr = src->getItra(sTranIdx-1u) ; 
0339         dTranIdx = 1u + dst->addTran( tra, itr ) ;
0340     }
0341 
0342     CSGNode nd = {} ; 
0343     CSGNode::Copy(nd, *snd ); // dumb straight copy : so need to fix transform and plan references   
0344 
0345     CSGNode* dnd = dst->addNode(nd, &splanes, nullptr);
0346 
0347     dnd->setTransformComplement( dTranIdx, complement ); 
0348 
0349     if( identical )
0350     {
0351         assert( dnd->planeNum() == snd->planeNum() );  
0352         assert( dnd->planeIdx() == snd->planeIdx() ); 
0353     }
0354 
0355     bool negated = dnd->is_complemented_primitive();
0356     bool zero = dnd->typecode() == CSG_ZERO ; 
0357     bool include_bb = negated == false && zero == false ; 
0358 
0359     float* naabb = dnd->AABB();   
0360 
0361     // negated nodes are not included into the prim bb
0362     if(include_bb)  
0363     {
0364         if( identical_bbox_cheat )
0365         {
0366             LOG(debug) << " identical_bbox_cheat : do nothing : as dumb CSGNode::Copy already copies bbox ";  
0367         }
0368         else
0369         {
0370             dnd->setAABBLocal() ; // reset to local with no transform applied
0371             if(tra) tra->transform_aabb_inplace( naabb );
0372 #ifdef WITH_S_BB
0373             prim_bb.include_aabb_widen( naabb );
0374 #else
0375             prim_bb.include_aabb( naabb );
0376 #endif
0377         }
0378     } 
0379 
0380     //if(dump_node) LOG(LEVEL) 
0381     if(dump_node) std::cout 
0382         << " nd " << std::setw(6) << nodeIdx 
0383         << " tc " << std::setw(4) << stypecode 
0384         << " st " << std::setw(4) << sTranIdx 
0385         << " dt " << std::setw(4) << dTranIdx 
0386         << " cn " << std::setw(12) << CSG::Name(stypecode) 
0387         << " hp " << has_planes
0388         << " ht " << has_transform
0389         << " ng " << negated
0390         << " ib " << include_bb
0391 #ifdef WITH_S_BB
0392         << " bb " << s_bb::Desc(naabb) 
0393 #else
0394         << " bb " << AABB::Desc(naabb) 
0395 #endif
0396         << std::endl 
0397         ; 
0398 }
0399 
0400 
0401 /**
0402 CSGCopy::copySolidInstances
0403 -------------------------------
0404 
0405 As some solids may disappear as a result of Prim selection 
0406 it is necessary to change potentially all the inst solid references. 
0407 
0408 See ~/j/issues/cxr_scan_cxr_overview_ELV_scan_out_of_range_error.rst
0409 
0410 Iterates over all source instances looking up the src gas_idx and 
0411 checking if that solid is selected and hence is being copied into the dst 
0412 geometry. Where instances correspond to selected solids the addInstance
0413 is invoked on the destination geometry.  
0414 
0415 **/
0416 
0417 void CSGCopy::copySolidInstances()
0418 {
0419     unsigned sNumInst = src->getNumInst(); 
0420 
0421     LOG(LEVEL) << " sNumInst " << sNumInst ;  
0422 
0423     for(unsigned i=0 ; i < sNumInst ; i++)
0424     {
0425         int sInstIdx = i ; 
0426         const qat4* ins = src->getInst(sInstIdx) ; 
0427 
0428         int ins_idx,  gas_idx, sensor_identifier, sensor_index ;
0429         ins->getIdentity(ins_idx,  gas_idx, sensor_identifier, sensor_index ); 
0430 
0431         LOG(debug)
0432             << " sInstIdx " << sInstIdx
0433             << " ins_idx " << ins_idx
0434             << " gas_idx " << gas_idx
0435             << " sensor_identifier " << sensor_identifier
0436             << " sensor_index " << sensor_index
0437             ;
0438 
0439         assert( ins_idx == sInstIdx ); 
0440         assert( gas_idx < int(sNumSolid) ); 
0441 
0442         int sSolidIdx = gas_idx ; 
0443         int dSolidIdx = solidMap[sSolidIdx] ; 
0444         // need to use dSolidIdx to prevent gas_refs going stale on selection
0445 
0446         if( dSolidIdx > -1 )
0447         {
0448             const float* tr16 = ins->cdata(); 
0449             bool firstcall = false ; // NOT FIRST CALL : SO DO NOT INCREMENT sensor_identifier
0450             dst->addInstance(tr16,  dSolidIdx, sensor_identifier, sensor_index, firstcall ); 
0451         }
0452     }
0453 }
0454