Back to home page

EIC code displayed by LXR

 
 

    


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

0001 #include <array>
0002 #include <csignal>
0003 
0004 #include "scuda.h"
0005 #include "squad.h"
0006 #include "stran.h"
0007 #include "ssys.h"
0008 #include "OpticksCSG.h"
0009 
0010 #include "SLOG.hh"
0011 
0012 #include "CSGNode.h"
0013 #include "CSGFoundry.h"
0014 #include "CSGMaker.h"
0015 
0016 const plog::Severity CSGMaker::LEVEL = SLOG::EnvLevel("CSGMaker", "DEBUG" ); 
0017 
0018 CSGMaker::CSGMaker( CSGFoundry* fd_ )
0019     :
0020     fd(fd_)
0021 {
0022 }
0023 
0024 bool CSGMaker::StartsWith( const char* n, const char* q ) // static
0025 {
0026     return strlen(q) >= strlen(n) && strncmp(q, n, strlen(n)) == 0 ; 
0027 }
0028 
0029 
0030 
0031 void CSGMaker::GetNames(std::vector<std::string>& names ) // static
0032 {
0033     std::stringstream ss(NAMES) ;    
0034     std::string name ; 
0035     while (std::getline(ss, name)) if(!name.empty()) names.push_back(name); 
0036 }
0037 
0038 
0039 /**
0040 CSGMaker::CanMake
0041 ------------------
0042 
0043 returns true when one of the listed NAMES starts with the query name. 
0044 CAUTION regards common prefixes. 
0045 
0046 **/
0047 bool CSGMaker::CanMake(const char* qname) // static 
0048 {
0049     bool found = false ; 
0050     std::stringstream ss(NAMES) ;    
0051     std::string name ; 
0052     while (!found && std::getline(ss, name)) if(!name.empty() && StartsWith(name.c_str(), qname)) found = true ;
0053     //LOG(LEVEL) << " qname " << qname << " found " << found ; 
0054     return found ; 
0055 }
0056 
0057 const char* CSGMaker::NAMES = R"LITERAL(
0058 JustOrb
0059 BoxedSphere
0060 ZSphere
0061 Cone
0062 Hyperboloid
0063 Box3
0064 Plane
0065 Slab
0066 Cylinder
0067 OldCylinder
0068 Disc
0069 ConvexPolyhedronCube
0070 ConvexPolyhedronTetrahedron
0071 Ellipsoid
0072 UnionBoxSphere
0073 UnionListBoxSphere
0074 UnionLLBoxSphere
0075 IntersectionBoxSphere
0076 OverlapBoxSphere
0077 OverlapThreeSphere
0078 ContiguousThreeSphere
0079 DiscontiguousThreeSphere
0080 DiscontiguousTwoSphere
0081 ContiguousBoxSphere
0082 DiscontiguousBoxSphere
0083 DifferenceBoxSphere
0084 ListTwoBoxTwoSphere
0085 RotatedCylinder
0086 DifferenceCylinder
0087 InfCylinder
0088 InfPhiCut
0089 InfThetaCut
0090 InfThetaCutL
0091 BoxSubSubCylinder
0092 )LITERAL"; 
0093 
0094 // see CSGNode::MakeDemo for CSGNode level equivalent
0095 CSGSolid* CSGMaker::make(const char* name)
0096 {
0097     CSGSolid* so = nullptr ; 
0098     if(     StartsWith("JustOrb", name))     so = makeSphere(name) ;
0099     else if(StartsWith("BoxedSphere", name)) so = makeBoxedSphere(name) ;
0100     else if(StartsWith("ZSphere", name))     so = makeZSphere(name) ;
0101     else if(StartsWith("Cone", name))        so = makeCone(name) ;
0102     else if(StartsWith("Hyperboloid", name)) so = makeHyperboloid(name) ;
0103     else if(StartsWith("Box3", name))        so = makeBox3(name) ;
0104     else if(StartsWith("Plane", name))       so = makePlane(name) ;
0105     else if(StartsWith("Slab", name))        so = makeSlab(name) ;
0106     else if(StartsWith("Cylinder", name))    so = makeCylinder(name) ;
0107     else if(StartsWith("OldCylinder", name)) so = makeOldCylinder(name) ;
0108     else if(StartsWith("Disc", name))     so = makeDisc(name) ;
0109     else if(StartsWith("ConvexPolyhedronCube", name))        so = makeConvexPolyhedronCube(name) ;
0110     else if(StartsWith("ConvexPolyhedronTetrahedron", name)) so = makeConvexPolyhedronTetrahedron(name) ;
0111     else if(StartsWith("Ellipsoid", name)) so = makeEllipsoid(name) ;
0112     else if(StartsWith("UnionBoxSphere", name))        so = makeUnionBoxSphere(name) ;
0113     else if(StartsWith("UnionListBoxSphere", name))    so = makeUnionListBoxSphere(name) ;
0114     else if(StartsWith("UnionLLBoxSphere", name))      so = makeUnionLLBoxSphere(name) ;
0115     else if(StartsWith("IntersectionBoxSphere", name)) so = makeIntersectionBoxSphere(name) ;
0116     else if(StartsWith("OverlapBoxSphere", name))      so = makeOverlapBoxSphere(name) ;
0117     else if(StartsWith("OverlapThreeSphere", name))    so = makeOverlapThreeSphere(name) ;
0118     else if(StartsWith("ContiguousThreeSphere", name))    so = makeContiguousThreeSphere(name) ;
0119     else if(StartsWith("DiscontiguousThreeSphere", name))    so = makeDiscontiguousThreeSphere(name) ;
0120     else if(StartsWith("DiscontiguousTwoSphere", name))    so = makeDiscontiguousTwoSphere(name) ;
0121     else if(StartsWith("ContiguousBoxSphere", name))   so = makeContiguousBoxSphere(name) ;
0122     else if(StartsWith("DiscontiguousBoxSphere", name))   so = makeDiscontiguousBoxSphere(name) ;
0123     else if(StartsWith("DifferenceBoxSphere", name))   so = makeDifferenceBoxSphere(name) ;
0124     else if(StartsWith("ListTwoBoxTwoSphere", name))   so = makeListTwoBoxTwoSphere(name); 
0125     else if(StartsWith("RotatedCylinder", name)) so = makeRotatedCylinder(name) ;
0126     else if(StartsWith("DifferenceCylinder", name)) so = makeDifferenceCylinder(name) ;
0127     else if(StartsWith("InfCylinder", name)) so = makeInfCylinder(name) ;
0128     else if(StartsWith("InfPhiCut", name)) so = makeInfPhiCut(name) ;
0129     else if(StartsWith("InfThetaCut", name)) so = makeInfThetaCut(name) ;
0130     else if(StartsWith("InfThetaCutL", name)) so = makeInfThetaCutL(name) ;
0131     else if(StartsWith("BoxSubSubCylinder", name)) so = makeBoxSubSubCylinder(name) ;
0132     else 
0133     {
0134         LOG(fatal) << "invalid name [" << name << "]" << " expecting one of the below " << std::endl << NAMES  ; 
0135         LOG(error) << "perhaps you intended to convert from a G4VSolid : if so see ~/opticks/GeoChain/translate.sh " ; 
0136     }
0137     assert( so ); 
0138     return so ;  
0139 }
0140 
0141 
0142 
0143 void CSGMaker::makeDemoSolids()
0144 {
0145     makeSphere(); 
0146     makeZSphere(); 
0147     makeCone(); 
0148     makeHyperboloid(); 
0149     makeBox3(); 
0150     makePlane(); 
0151     makeSlab(); 
0152     makeCylinder() ; 
0153     makeDisc(); 
0154     makeConvexPolyhedronCube(); 
0155     makeConvexPolyhedronTetrahedron(); 
0156     makeEllipsoid(); 
0157     makeUnionBoxSphere();
0158     makeIntersectionBoxSphere();
0159     makeDifferenceBoxSphere();
0160     makeRotatedCylinder();
0161     makeDifferenceCylinder();
0162     makeBoxSubSubCylinder();
0163 }
0164 
0165 void CSGMaker::makeDemoGrid()
0166 {
0167     makeDemoSolids(); 
0168     unsigned num_solids = fd->getNumSolid(); 
0169     LOG(info) << " num_solids " << num_solids ; 
0170 
0171     float gridscale = 100.f ; 
0172     std::array<int,9> grid = {{ -10,11,2,  -10,11,2, -10,11,2  }} ;
0173 
0174     unsigned count = 0 ; 
0175 
0176     for(int i=grid[0] ; i < grid[1] ; i+=grid[2] ){
0177     for(int j=grid[3] ; j < grid[4] ; j+=grid[5] ){
0178     for(int k=grid[6] ; k < grid[7] ; k+=grid[8] ){
0179 
0180         qat4 instance  ;   
0181         instance.q3.f.x = float(i)*gridscale ; 
0182         instance.q3.f.y = float(j)*gridscale ; 
0183         instance.q3.f.z = float(k)*gridscale ; 
0184         
0185         unsigned ins_idx = fd->inst.size() ;    
0186         unsigned gas_idx = count % num_solids ; 
0187         unsigned sensor_identifier = 0 ;   // HMM: thats a valid identifier ? 
0188         unsigned sensor_index = 0 ; 
0189 
0190         instance.setIdentity( ins_idx, gas_idx, sensor_identifier, sensor_index );  
0191         fd->inst.push_back( instance );  
0192      
0193         count++ ; 
0194     }   
0195     }   
0196     }   
0197 }
0198 
0199 
0200 
0201 
0202 /**
0203 CSGMaker::makeLayered
0204 ----------------------------
0205 
0206 NB Each layer is a separate CSGPrim with a single CSGNode 
0207 
0208 NB the ordering of addition is prescribed, must stick 
0209 ridgidly to the below order of addition:
0210 
0211 1. addSolid
0212 2. addPrim
0213 3. addNode
0214 
0215 And the numbers of Prim and Node added 
0216 must correspond to the declarations. 
0217 
0218 Note that the CSGNode and CSGPrim can be created anytime, the 
0219 restriction is on the order of addition to the CSGFoundry 
0220 due to the capturing of offsets at collection. 
0221 
0222 **/
0223 
0224 CSGSolid* CSGMaker::makeLayered(const char* label, float outer_radius, unsigned layers )
0225 {
0226     std::vector<float> radii ;
0227     for(unsigned i=0 ; i < layers ; i++) radii.push_back(outer_radius*float(layers-i)/float(layers)) ; 
0228 
0229     unsigned numPrim = layers ; 
0230     CSGSolid* so = fd->addSolid(numPrim, label); 
0231     so->center_extent = make_float4( 0.f, 0.f, 0.f, outer_radius ) ; 
0232 
0233     for(unsigned i=0 ; i < numPrim ; i++)
0234     {
0235         unsigned numNode = 1 ; 
0236         int nodeOffset_ = -1 ; 
0237         CSGPrim* pr = fd->addPrim(numNode, nodeOffset_ );
0238  
0239         float radius = radii[i]; 
0240 
0241         CSGNode* nd = nullptr ; 
0242 
0243         if(strcmp(label, "sphere") == 0)
0244         {
0245             nd = fd->addNode(CSGNode::Sphere(radius)); 
0246         }
0247         else if(strcmp(label, "zsphere") == 0)
0248         {
0249             nd = fd->addNode(CSGNode::ZSphere(radius, -radius/2.f , radius/2.f )); 
0250         }
0251         else
0252         {
0253             assert( 0 && "layered only implemented for sphere and zsphere currently" ); 
0254         } 
0255 
0256         // pr->setSbtIndexOffset(i) ;  // NOW done in addPrim
0257         pr->setAABB( nd->AABB() ); 
0258     }
0259     return so ; 
0260 }
0261 
0262 
0263 /**
0264 CSGMaker::makeBoxedSphere
0265 --------------------------
0266 
0267 Add CSGSolid to CSGFoundry that is comprised of two CSGPrim, 
0268 each with a single CSGNode.  
0269 
0270    
0271      +--------------+
0272      |              | 
0273      |              | 
0274      |              | 
0275      |              | 
0276      |              | 
0277      |              | 
0278      +--------------+
0279 
0280 
0281 
0282 **/
0283 
0284 CSGSolid* CSGMaker::makeBoxedSphere(const char* label)
0285 {
0286     float halfside = ssys::getenvfloat("CSGMaker_makeBoxedSphere_HALFSIDE", 100.f); 
0287     float factor   = ssys::getenvfloat("CSGMaker_makeBoxedSphere_FACTOR", 1.f); 
0288     //LOG(LEVEL) << "CSGMaker_makeBoxedSphere_HALFSIDE " << halfside  ; 
0289     //LOG(LEVEL) << "CSGMaker_makeBoxedSphere_FACTOR   " << factor ; 
0290 
0291     float radius   = halfside/2.f ; 
0292     float box_halfside = halfside*factor ; 
0293 
0294 
0295     unsigned numPrim = 2 ; 
0296     CSGSolid* so = fd->addSolid(numPrim, label); 
0297     AABB bb = {} ; 
0298 
0299     for(unsigned i=0 ; i < numPrim ; i++)
0300     {
0301         CSGPrim* pr = fd->addPrim(1, -1);  // numNode, nodeOffset
0302         CSGNode* nd = nullptr ; 
0303         switch(i)
0304         {
0305             case 0: nd = fd->addNode(CSGNode::Box3(2.f*box_halfside)) ;  break ;   
0306             case 1: nd = fd->addNode(CSGNode::Sphere(radius))     ;  break ;   
0307         } 
0308         pr->setAABB( nd->AABB() ); 
0309         bb.include_aabb( nd->AABB() ); 
0310     }
0311 
0312     so->center_extent = bb.center_extent() ;  
0313     //LOG(info) << " so->center_extent " << so->center_extent ; 
0314 
0315     return so ; 
0316 }
0317 
0318 
0319 
0320 /**
0321 CSGMaker::makeScaled
0322 ----------------------
0323 
0324 Creates a CSGSolid composed of *layers* CSGPrim where each CSGPrim has one CSGNode
0325 with different scale transforms created and associated with each CSGNode to make 
0326 a Russian doll arrangement.  
0327 
0328 This demonstrates adding a transform and associating it to a CSGNode.  
0329 
0330 **/
0331 
0332 CSGSolid* CSGMaker::makeScaled(const char* label, const char* demo_node_type, float outer_scale, unsigned layers )
0333 {
0334     std::vector<float> scales ;
0335     for(unsigned i=0 ; i < layers ; i++) scales.push_back(outer_scale*float(layers-i)/float(layers)) ; 
0336 
0337     unsigned numPrim = layers ; 
0338     CSGSolid* so = fd->addSolid(numPrim, label); 
0339     AABB bb = {} ; 
0340 
0341     for(unsigned i=0 ; i < numPrim ; i++)
0342     {
0343         unsigned numNode = 1 ; 
0344         int nodeOffset_ = -1; 
0345         CSGPrim* pr = fd->addPrim(numNode, nodeOffset_); 
0346         CSGNode* nd = fd->addNode(CSGNode::MakeDemo(demo_node_type)) ;
0347     
0348         float scale = scales[i]; 
0349         const Tran<double>* tran_scale = Tran<double>::make_scale( double(scale), double(scale), double(scale) ); 
0350 
0351         /*
0352         unsigned transform_idx = 1 + fd->addTran(tran_scale);      // 1-based idx, 0 meaning None
0353         nd->setTransform(transform_idx); 
0354         const qat4* tr = fd->getTran(transform_idx-1u) ;   // storage uses 0-based 
0355         tr->transform_aabb_inplace( nd->AABB() ); 
0356         */
0357 
0358         bool transform_node_aabb = true ; 
0359         fd->addNodeTran( nd, tran_scale, transform_node_aabb ); 
0360 
0361 
0362         bb.include_aabb( nd->AABB() ); 
0363 
0364         // pr->setSbtIndexOffset(i) ;  //  NOW done in addPrim
0365         pr->setAABB( nd->AABB() ); 
0366     }
0367 
0368     so->center_extent = bb.center_extent() ;  
0369     LOG(info) << " so->center_extent " << so->center_extent ; 
0370 
0371     return so ; 
0372 }
0373 
0374 
0375 
0376 /**
0377 CSGMaker::makeClustered
0378 -------------------------
0379 
0380 
0381 **/
0382 
0383 CSGSolid* CSGMaker::makeClustered(const char* label,  int i0, int i1, int is, int j0, int j1, int js, int k0, int k1, int ks, double unit, bool inbox ) 
0384 {
0385     unsigned numPrim = inbox ? 1 : 0 ; 
0386     for(int i=i0 ; i < i1 ; i+=is ) 
0387     for(int j=j0 ; j < j1 ; j+=js ) 
0388     for(int k=k0 ; k < k1 ; k+=ks ) 
0389     {
0390         //LOG(info) << std::setw(2) << numPrim << " (i,j,k) " << "(" << i << "," << j << "," << k << ") " ; 
0391         numPrim += 1 ; 
0392     }
0393        
0394     LOG(info) 
0395         << " label " << label  
0396         << " numPrim " << numPrim 
0397         << " inbox " << inbox
0398         ;  
0399 
0400     CSGSolid* so = fd->addSolid(numPrim, label);
0401     unsigned idx = 0 ; 
0402 
0403     AABB bb = {} ; 
0404  
0405     for(int i=i0 ; i < i1 ; i+=is ) 
0406     for(int j=j0 ; j < j1 ; j+=js ) 
0407     for(int k=k0 ; k < k1 ; k+=ks ) 
0408     {
0409         unsigned numNode = 1 ; 
0410         int nodeOffset_ = -1 ;  // -1:use current node count as about to add the declared numNode
0411         CSGPrim* p = fd->addPrim(numNode, nodeOffset_); 
0412         CSGNode* n = fd->addNode(CSGNode::MakeDemo(label)) ;
0413     
0414         const Tran<double>* translate = Tran<double>::make_translate( double(i)*unit, double(j)*unit, double(k)*unit ); 
0415 
0416 
0417         unsigned transform_idx = 1 + fd->addTran(translate);      // 1-based idx, 0 meaning None
0418         n->setTransform(transform_idx); 
0419         const qat4* t = fd->getTran(transform_idx-1u) ; 
0420         t->transform_aabb_inplace( n->AABB() ); 
0421 
0422 
0423 
0424 
0425         bb.include_aabb( n->AABB() ); 
0426 
0427         // p->setSbtIndexOffset(idx) ;    //  now done in addPrim
0428         p->setAABB( n->AABB() );  // HUH : THIS SHOULD BE bb ?
0429 
0430         //DumpAABB("p->AABB() aft setup", p->AABB() ); 
0431         
0432         LOG(info) << " idx " << idx << " transform_idx " << transform_idx ; 
0433  
0434         idx += 1 ; 
0435     }
0436 
0437 
0438     if(inbox)
0439     {
0440         float4 ce = bb.center_extent(); 
0441         float fullside = ce.w*2.f ; 
0442 
0443         unsigned numNode = 1 ; 
0444         int nodeOffset_ = -1 ;  // -1:use current node count as about to add the declared numNode
0445 
0446         CSGPrim* p = fd->addPrim(numNode, nodeOffset_ ); 
0447         CSGNode bx = CSGNode::Box3(fullside) ;
0448         CSGNode* n = fd->addNode(bx); 
0449 
0450 
0451         const Tran<float>* to_center = Tran<float>::make_translate( float(ce.x), float(ce.y), float(ce.z) ); 
0452         unsigned transform_idx = 1 + fd->addTran(to_center);  // 1-based idx, 0 meaning None
0453         const qat4* t = fd->getTran(transform_idx-1u) ; 
0454 
0455         n->setTransform(transform_idx); 
0456         t->transform_aabb_inplace( n->AABB() ); 
0457 
0458         // p->setSbtIndexOffset(idx);   now done in addPrim
0459         p->setAABB( n->AABB() );
0460         
0461         idx += 1 ; 
0462     }
0463 
0464 
0465     so->center_extent = bb.center_extent() ;   // contains AABB of all CSGPrim 
0466     LOG(info) << " so->center_extent " << so->center_extent ; 
0467     return so ; 
0468 }
0469 
0470 /**
0471 CSGMaker::makeSolid11 makes 1-CSGPrim with 1-CSGNode
0472 ---------------------------------------------------------
0473 
0474 HMM: the absolute meshIdx here is causing out of range in CSGFoundry::getMeshName 
0475 when creating a single CSGSolid/CSGPrim/CSGNode  
0476 
0477 **/
0478 
0479 CSGSolid* CSGMaker::makeSolid11(const char* label, CSGNode nd, const std::vector<float4>* pl, int meshIdx, const Tran<double>* tr  ) 
0480 {
0481     unsigned numPrim = 1 ; 
0482     CSGSolid* so = fd->addSolid(numPrim, label);
0483 
0484     unsigned numNode = 1 ; 
0485     int nodeOffset_ = -1 ;  
0486     CSGPrim* p = fd->addPrim(numNode, nodeOffset_); 
0487     p->setMeshIdx(meshIdx); 
0488 
0489     CSGNode* n = fd->addNode(nd, pl, tr ); 
0490     p->setAABB( n->AABB() ); 
0491 
0492     float extent = p->extent(); 
0493     LOG_IF(fatal, extent == 0.f) << "FATAL : " << label << " : got zero extent " ; 
0494     //assert( extent > 0.f ); 
0495 
0496     AABB bb = AABB::Make( p->AABB() ); 
0497     so->center_extent = bb.center_extent()  ; 
0498     //LOG(info) << "so.getLabel " << so->getLabel() << " so.center_extent " << so->center_extent ; 
0499     return so ; 
0500 }
0501 
0502 CSGSolid* CSGMaker::makeBooleanBoxSphere( const char* label, unsigned op_, float radius, float fullside, int meshIdx )
0503 {
0504     LOG(LEVEL) << " fullside " << fullside << " radius " << radius ; 
0505     CSGNode bx = CSGNode::Box3(fullside) ; 
0506     CSGNode sp = CSGNode::Sphere(radius); 
0507     return makeBooleanTriplet(label, op_, bx, sp ); 
0508 }
0509 
0510 
0511 /**
0512 CSGMaker::makeBooleanTriplet
0513 ------------------------------
0514 
0515 Note convention that by-value CSGNode arguments are to be added to CSGFoundry
0516 (ie assumed not already added) as opposed by pointer CSGNode arguments, which imply 
0517 the nodes are already added to the CSGFoundry. 
0518 
0519           op
0520 
0521       left   right 
0522 
0523 
0524 
0525  
0526 **/
0527 
0528 CSGSolid* CSGMaker::makeBooleanTriplet( const char* label, unsigned op_, const CSGNode& left, const CSGNode& right, int meshIdx ) 
0529 {
0530     unsigned numPrim = 1 ; 
0531     CSGSolid* so = fd->addSolid(numPrim, label);
0532 
0533     unsigned numNode = 3 ; 
0534     int nodeOffset_ = -1 ; 
0535     CSGPrim* p = fd->addPrim(numNode, nodeOffset_ ); 
0536     if(meshIdx > -1) p->setMeshIdx(meshIdx);
0537 
0538     CSGNode op = CSGNode::BooleanOperator(op_, -1);  // CHANGED 3 to -1 as this is standard boolean ?
0539     CSGNode* n = fd->addNode(op); 
0540 
0541     CSGNode* root = n ;  
0542     // cf CSGImport::importPrim 
0543     root->setSubNum(numNode); // avoids notes/issues/CSGScanTest_with_CSGMaker_solids_not_intersecting_booleans.rst
0544     root->setSubOffset(0); 
0545 
0546 
0547     fd->addNode(left); 
0548     fd->addNode(right); 
0549      
0550     // naive bbox combination yields overlarge bbox, not appropriate for production code
0551     AABB bb = {} ;
0552     bb.include_aabb( left.AABB() );     // assumes any transforms have been applied to the Node AABB
0553     bb.include_aabb( right.AABB() ); 
0554     p->setAABB( bb.data() );  
0555 
0556     so->center_extent = bb.center_extent()  ; 
0557 
0558     // setting transform as otherise loading foundry fails for lack of non-optional tran array 
0559     //const Tran<double>* tran_identity = Tran<double>::make_identity(); 
0560     unsigned transform_idx = 1 + fd->addTran();   // 1-based idx, 0 meaning None
0561     n->setTransform(transform_idx); 
0562 
0563 
0564     //LOG(LEVEL) << "so.label " << so->getLabel() << " so.center_extent " << so->center_extent ; 
0565     return so ; 
0566 }
0567 
0568 
0569 
0570 
0571 
0572 
0573 CSGSolid* CSGMaker::makeOverlapBoxSphere( const char* label, float radius, float fullside )
0574 {
0575     CSGNode bx = CSGNode::Box3(fullside) ; 
0576     CSGNode sp = CSGNode::Sphere(radius); 
0577 
0578     std::vector<CSGNode> leaves ; 
0579     leaves.push_back(bx); 
0580     leaves.push_back(sp); 
0581 
0582     return makeOverlapList( label, leaves, nullptr ); 
0583 }
0584 
0585 /**
0586 
0587                                     Y        
0588 
0589               (-side,side)          |             (side, side)
0590                          +          |             +
0591                                     |  
0592                                     |  
0593                                     |  
0594                                     |  
0595                                     |  
0596                       --------------O---------=---------  X
0597                                     |  
0598                                     |  
0599                                     |  
0600                                     |  
0601                                     |  
0602                                     |  
0603                                     +
0604                                     | ( 0, -side*sqrt(2))
0605                                     |  
0606 
0607 
0608                
0609 
0610 **/
0611 CSGSolid* CSGMaker::makeListThreeSphere( const char* label, unsigned type, float radius, float side )
0612 {
0613     CSGNode s0 = CSGNode::Sphere(radius); 
0614     CSGNode s1 = CSGNode::Sphere(radius); 
0615     CSGNode s2 = CSGNode::Sphere(radius); 
0616 
0617     const Tran<double>* t0 = Tran<double>::make_translate(  side,  side         , 0. ); 
0618     const Tran<double>* t1 = Tran<double>::make_translate( -side,  side         , 0. ); 
0619     const Tran<double>* t2 = Tran<double>::make_translate(    0., -side*sqrt(2.), 0. ); 
0620 
0621 
0622     std::vector<CSGNode> leaves ; 
0623     leaves.push_back(s0); 
0624     leaves.push_back(s1); 
0625     leaves.push_back(s2); 
0626 
0627     std::vector<const Tran<double>*> tran ; 
0628     tran.push_back(t0); 
0629     tran.push_back(t1); 
0630     tran.push_back(t2); 
0631 
0632     return makeList( label, type, leaves, &tran ); 
0633 }
0634 
0635 CSGSolid* CSGMaker::makeOverlapThreeSphere( const char* label, float radius, float side )
0636 {
0637     return makeListThreeSphere( label, CSG_OVERLAP , radius, side ); 
0638 }
0639 /**
0640 CSGMaker::makeContiguousThreeSphere
0641 ---------------------------------------
0642 radius 100.f side 50.f 
0643 
0644 
0645     (-side,side,0)          (side,side,0)    
0646     (-50,50,0)              (50,50,0) 
0647         s1         |         s0 
0648           +        |         +
0649                    |
0650                    |
0651           ---------O-----------
0652                    |
0653                    |
0654                    +
0655                   s2
0656                 (0,-70,0)
0657                (0,-side*sqrt(2),0)
0658 
0659 
0660 TIP: for debugging temporarily switch to CSG_DISCONTIGUOUS in order to see the separate spheres
0661 **/
0662 
0663 CSGSolid* CSGMaker::makeContiguousThreeSphere( const char* label, float radius, float side )
0664 {
0665     return makeListThreeSphere( label, CSG_CONTIGUOUS , radius, side ); 
0666 }
0667 
0668 /**
0669 CSGMaker::makeDiscontiguousThreeSphere
0670 -----------------------------------------
0671 
0672 radius 100.f side 100.f 
0673 
0674     (-side,side,0)          (side,side,0)    
0675     (-100,100,0)            (100,100,0) 
0676      s1            |            s0 
0677       +            |             +
0678                    |
0679                    |
0680                    |
0681                    |
0682                    |
0683           ---------O-----------
0684                    |
0685                    |
0686                    |
0687                    |
0688                    |
0689                    |
0690                    +
0691                   s2
0692                 (0,-170,0)
0693                (0,-side*sqrt(2),0)
0694 
0695 
0696 **/
0697 
0698 CSGSolid* CSGMaker::makeDiscontiguousThreeSphere( const char* label, float radius, float side )
0699 {
0700     return makeListThreeSphere( label, CSG_DISCONTIGUOUS , radius, side ); 
0701 }
0702 
0703 
0704 /**
0705 CSGMaker::makeDiscontiguousTwoSphere
0706 -------------------------------------
0707 
0708 Checking the sense of the transforms : get the expected ones. 
0709 
0710 
0711                    Y
0712     (-100,200)     |
0713     (-side, 2*side)|
0714          t1        |
0715            +       |
0716                    |
0717                    |
0718                    |      +   t0 (side, 0.5*side)    (100,50)
0719                    |                            
0720                    |
0721         -----------O------------------------------ X
0722 
0723 **/
0724 
0725 CSGSolid* CSGMaker::makeDiscontiguousTwoSphere( const char* label, float radius, float side )
0726 {
0727     return makeListTwoSphere( label, CSG_DISCONTIGUOUS , radius, side ); 
0728 }
0729 
0730 CSGSolid* CSGMaker::makeListTwoSphere( const char* label, unsigned type, float radius, float side )
0731 {
0732     CSGNode s0 = CSGNode::Sphere(radius); 
0733     CSGNode s1 = CSGNode::Sphere(radius); 
0734 
0735     const Tran<double>* t0 = Tran<double>::make_translate(  side,  0.5*side     , 0. ); 
0736     const Tran<double>* t1 = Tran<double>::make_translate( -side,  2.0*side      , 0. ); 
0737 
0738     std::vector<CSGNode> leaves ; 
0739     leaves.push_back(s0); 
0740     leaves.push_back(s1); 
0741 
0742     std::vector<const Tran<double>*> tran ; 
0743     tran.push_back(t0); 
0744     tran.push_back(t1); 
0745  
0746     return makeList( label, type, leaves, &tran ); 
0747 }
0748 
0749 
0750 
0751 
0752 CSGSolid* CSGMaker::makeContiguousBoxSphere( const char* label, float radius, float fullside )
0753 {
0754     CSGNode bx = CSGNode::Box3(fullside) ; 
0755     CSGNode sp = CSGNode::Sphere(radius); 
0756 
0757     std::vector<CSGNode> leaves ; 
0758     leaves.push_back(bx); 
0759     leaves.push_back(sp); 
0760 
0761     return makeContiguousList( label, leaves, nullptr ); 
0762 }
0763 
0764 CSGSolid* CSGMaker::makeDiscontiguousBoxSphere( const char* label, float radius, float fullside )
0765 {
0766     CSGNode bx = CSGNode::Box3(fullside) ; 
0767     CSGNode sp = CSGNode::Sphere(radius); 
0768 
0769     const Tran<double>* bx_shift = Tran<double>::make_translate( fullside, 0., 0. ) ;  
0770     const Tran<double>* sp_shift = Tran<double>::make_translate(-fullside, 0., 0. ) ;  
0771 
0772     std::vector<CSGNode> leaves ; 
0773     leaves.push_back(bx); 
0774     leaves.push_back(sp); 
0775 
0776     std::vector<const Tran<double>*> trans ;
0777     trans.push_back(bx_shift); 
0778     trans.push_back(sp_shift); 
0779 
0780     return makeDiscontiguousList( label, leaves, &trans ); 
0781 }
0782 
0783 
0784 
0785 
0786 CSGSolid* CSGMaker::makeOverlapList(       const char* label, std::vector<CSGNode>& leaves, const std::vector<const Tran<double>*>* tran )
0787 {  
0788     return makeList( label, CSG_OVERLAP, leaves, tran ); 
0789 }
0790 CSGSolid* CSGMaker::makeContiguousList(    const char* label, std::vector<CSGNode>& leaves, const std::vector<const Tran<double>*>* tran  )
0791 { 
0792     return makeList( label, CSG_CONTIGUOUS, leaves, tran ); 
0793 }
0794 CSGSolid* CSGMaker::makeDiscontiguousList( const char* label, std::vector<CSGNode>& leaves, const std::vector<const Tran<double>*>* tran  )
0795 { 
0796     return makeList( label, CSG_DISCONTIGUOUS, leaves, tran ); 
0797 }
0798 
0799 
0800 CSGSolid* CSGMaker::makeList( const char* label, unsigned type, std::vector<CSGNode>& leaves, const std::vector<const Tran<double>*>* tran )
0801 {
0802     unsigned numSub = leaves.size() ; 
0803     unsigned numTran = tran ? tran->size() : 0  ; 
0804     if( numTran > 0 ) assert( numSub == numTran );
0805  
0806     unsigned numPrim = 1 ; 
0807     CSGSolid* so = fd->addSolid(numPrim, label);
0808     
0809     unsigned numNode = 1 + numSub ; 
0810     int nodeOffset_ = -1 ; 
0811     CSGPrim* p = fd->addPrim(numNode, nodeOffset_ ); 
0812 
0813     unsigned subOffset = 1 ; // now using absolute offsets from "root" to the first sub  see notes/issues/ContiguousThreeSphere.rst
0814     CSGNode hdr = CSGNode::ListHeader(type, numSub, subOffset ); 
0815     CSGNode* n = fd->addNode(hdr); 
0816 
0817     AABB bb = {} ;
0818     fd->addNodes( bb, leaves, tran ); 
0819     p->setAABB( bb.data() );  
0820     so->center_extent = bb.center_extent()  ; 
0821 
0822     fd->addNodeTran(n);   // setting identity transform 
0823     
0824     //LOG(LEVEL) << "so.label " << so->getLabel() << " so.center_extent " << so->center_extent ; 
0825 
0826     return so ; 
0827 }
0828 
0829 
0830 /**
0831 CSGMaker::makeUnionListBoxSphere
0832 ---------------------------------
0833 
0834 This is for testing a tree with a compound node within it  
0835 
0836 
0837           op
0838          /  \
0839         bx  (co)  
0840              |
0841              sp 
0842 
0843 
0844 List notes require subNum and subOffset to identify the referenced sequence of sub-nodes. 
0845 The subOffset in a tree with only a single list will simply be the number of tree nodes 
0846 which is 3 in this simple example. 
0847 For larger trees it will be the number of nodes in the complete binary tree 
0848 which will be: 3, 7, 15, 31  
0849 
0850 When more than one list the subOffset will need to be arranged to 
0851 skip over the subs of other lists. 
0852 
0853 **/
0854 
0855 CSGSolid* CSGMaker::makeUnionListBoxSphere( const char* label, float radius, float fullside )
0856 {
0857     // 3 tree nodes + 1 sub-node from the compound
0858     CSGNode op    = CSGNode::BooleanOperator(CSG_UNION, 3); 
0859     CSGNode left  = CSGNode::Box3(fullside) ; 
0860 
0861     int subNum = 1 ;    // number of subs referenced by the List node
0862     int subOffset = op.subNum() ; 
0863     CSGNode right = CSGNode::ListHeader(CSG_CONTIGUOUS, subNum, subOffset ); 
0864     CSGNode sub   = CSGNode::Sphere(radius); 
0865 
0866     unsigned numPrim = 1 ; 
0867     CSGSolid* so = fd->addSolid(numPrim, label);
0868 
0869     unsigned numNode = 3 + subNum ; 
0870     int nodeOffset_ = -1 ; 
0871     CSGPrim* p = fd->addPrim(numNode, nodeOffset_ ); 
0872 
0873     CSGNode* root = fd->addNode(op);   
0874     CSGNode* l    = fd->addNode(left); 
0875     CSGNode* r    = fd->addNode(right); 
0876     CSGNode* s    = fd->addNode(sub); 
0877 
0878     bool root_expect = root->typecode() == CSG_UNION ;
0879     bool l_expect = l->typecode() == CSG_BOX3 ;
0880     bool r_expect = r->typecode() == CSG_CONTIGUOUS ; 
0881     bool s_expect = s->typecode() == CSG_SPHERE ; 
0882     bool op_expect =  op.subNum() == 3 && root->subNum() == 3  ; 
0883 
0884     assert( root_expect ); 
0885     assert( l_expect ); 
0886     assert( r_expect ); 
0887     assert( s_expect ); 
0888     assert( op_expect ); 
0889 
0890     if(!root_expect) std::raise(SIGINT); 
0891     if(!l_expect) std::raise(SIGINT); 
0892     if(!r_expect) std::raise(SIGINT); 
0893     if(!s_expect) std::raise(SIGINT); 
0894     if(!op_expect) std::raise(SIGINT); 
0895 
0896     AABB bb = {} ;
0897     bb.include_aabb( right.AABB() ); 
0898     bb.include_aabb( sub.AABB() ); 
0899     p->setAABB( bb.data() );  
0900     so->center_extent = bb.center_extent()  ; 
0901 
0902     fd->addNodeTran(root);  // adding identity, as geometry must have at least one transform
0903 
0904     //LOG(LEVEL) << "so.label " << so->getLabel() << " so.center_extent " << so->center_extent ; 
0905     return so ; 
0906 }
0907 
0908 
0909 /**
0910 CSGMaker::makeBooleanListList
0911 -------------------------------
0912 
0913 This generalizes from CSGMaker::makeUnionListBoxSphere in order to test in a more flexible way.
0914 
0915 TODO: need to apply the experience from here to the GeoChain conversions with CSG_CONTIGUOUS hinting, 
0916 should the subOffset be set at NCSG level ?
0917 
0918 **/
0919 
0920 CSGSolid* CSGMaker::makeBooleanListList( const char* label, 
0921        unsigned op_, 
0922        unsigned ltype,
0923        unsigned rtype,  
0924        std::vector<CSGNode>& lhs, 
0925        std::vector<CSGNode>& rhs, 
0926        const std::vector<const Tran<double>*>* ltran,
0927        const std::vector<const Tran<double>*>* rtran
0928     )
0929 {
0930     unsigned num_left  = lhs.size(); 
0931     unsigned num_right = rhs.size(); 
0932     assert( num_left > 0 && num_right > 0 ); 
0933 
0934     // singles on left or right are inlined into the boolean so no addition beyond the tree
0935     unsigned numNode = 3 + ( num_left == 1 ? 0 : num_left ) + ( num_right == 1 ? 0 : num_right )  ; 
0936 
0937     unsigned numPrim = 1 ; 
0938     CSGSolid* so = fd->addSolid(numPrim, label);
0939 
0940     int nodeOffset_ = -1 ; 
0941     CSGPrim* p = fd->addPrim(numNode, nodeOffset_ ); 
0942 
0943     CSGNode op    = CSGNode::BooleanOperator(op_, 3); 
0944     CSGNode* root = fd->addNode(op); 
0945 
0946     unsigned subOffset = 0 ; 
0947     subOffset += root->subNum() ;  
0948     assert( subOffset == 3 );   // 3 tree nodes
0949 
0950 
0951     AABB bb = {} ;
0952 
0953     if( num_left == 1 && num_right == 1 )
0954     {
0955         const CSGNode& left = lhs[0]; 
0956         const CSGNode& right = rhs[0]; 
0957 
0958         fd->addNode(bb, left); 
0959         fd->addNode(bb, right); 
0960     }
0961     else if( num_left > 1 && num_right == 1 )
0962     {
0963         CSGNode left = CSGNode::ListHeader(ltype, num_left, subOffset ); 
0964         subOffset += num_left ; 
0965 
0966         const CSGNode& right = rhs[0]; 
0967 
0968         fd->addNode(left); 
0969         fd->addNode(bb, right); 
0970         fd->addNodes(bb, lhs, ltran); 
0971     }
0972     else if( num_left == 1 && num_right > 1 )
0973     {
0974         CSGNode left = lhs[0] ; 
0975         CSGNode right = CSGNode::ListHeader(rtype, num_right, subOffset ); 
0976         subOffset += num_right ; 
0977 
0978         fd->addNode(bb, left); 
0979         fd->addNode(right); 
0980         fd->addNodes(bb, rhs, rtran); 
0981     }
0982     else if( num_left > 1 && num_right > 1 )
0983     {
0984         CSGNode left = CSGNode::ListHeader(ltype, num_left, subOffset ); 
0985         subOffset += num_left ; 
0986 
0987         CSGNode right = CSGNode::ListHeader(rtype, num_right, subOffset ); 
0988         subOffset += num_right ; 
0989 
0990         fd->addNode(left); 
0991         fd->addNode(right); 
0992 
0993         fd->addNodes( bb, lhs, ltran ); 
0994         fd->addNodes( bb, rhs, rtran ); 
0995     }
0996 
0997 
0998     p->setAABB( bb.data() );  
0999     so->center_extent = bb.center_extent()  ; 
1000 
1001     fd->addNodeTran(root);  // adding identity, as geometry must have at least one transform
1002     
1003     return so ; 
1004 }
1005 
1006 
1007 /**
1008 CSGMaker::makeUnionLLBoxSphere
1009 --------------------------------
1010 
1011 radius=100.f fullside=100.f
1012 
1013 
1014                                    (-50,100)                  (50,100)
1015                                     +                           +
1016                           .                 .             .            .
1017                                                    +  
1018                      .                                                       .
1019                                               .           . 
1020  
1021                   .                                                                 .
1022                                          .
1023 
1024               .                       .                       \                        .
1025              
1026                                
1027            -|-----------------------s0-------------O------------|s1--------------------|-------------
1028                               (-50,0,0)                       (50,0,0)                        
1029 
1030               \                        \                      /                       /
1031 
1032 
1033                    
1034                  
1035                                                     +
1036 
1037 
1038                                     +                           +
1039                                   (-50,-100)                 (50, -100)
1040 
1041 
1042             |          |            |             |            |           |          |
1043           -150        -100         -50            0            50         100        150
1044           
1045 **/
1046 
1047 CSGSolid* CSGMaker::makeUnionLLBoxSphere( const char* label, float radius, float fullside  )
1048 {
1049     std::vector<CSGNode> lhs ; 
1050     lhs.push_back( CSGNode::Sphere(radius) ); 
1051     lhs.push_back( CSGNode::Sphere(radius) ); 
1052 
1053     std::vector<const Tran<double>*> ltran ;
1054     ltran.push_back(Tran<double>::make_translate( -radius/2., 0., 0. )) ;
1055     ltran.push_back(Tran<double>::make_translate(  radius/2., 0., 0. )) ;
1056 
1057     std::vector<CSGNode> rhs ; 
1058     rhs.push_back( CSGNode::Box3(fullside) ); 
1059     rhs.push_back( CSGNode::Box3(fullside) ); 
1060 
1061     std::vector<const Tran<double>*> rtran ;
1062     rtran.push_back(Tran<double>::make_translate(   0.,  fullside, 0. )) ;
1063     rtran.push_back(Tran<double>::make_translate(   0., -fullside, 0. )) ;
1064 
1065     unsigned btype = CSG_DIFFERENCE ; 
1066     unsigned ltype = CSG_CONTIGUOUS ; 
1067     unsigned rtype = CSG_DISCONTIGUOUS  ;   
1068 
1069     return makeBooleanListList(label, btype, ltype, rtype, lhs, rhs, &ltran, &rtran ); 
1070 }
1071 
1072 CSGSolid* CSGMaker::makeListTwoBoxTwoSphere( const char* label, float radius, float fullside  )
1073 {
1074     std::vector<CSGNode> leaves ; 
1075     leaves.push_back( CSGNode::Sphere(radius) ); 
1076     leaves.push_back( CSGNode::Sphere(radius) ); 
1077     leaves.push_back( CSGNode::Box3(fullside) ); 
1078     leaves.push_back( CSGNode::Box3(fullside) ); 
1079 
1080     std::vector<const Tran<double>*> tran ;
1081     tran.push_back(Tran<double>::make_translate( -radius/2., 0., 0. )) ;
1082     tran.push_back(Tran<double>::make_translate(  radius/2., 0., 0. )) ;
1083     tran.push_back(Tran<double>::make_translate(   0.,  fullside, 0. )) ;
1084     tran.push_back(Tran<double>::make_translate(   0., -fullside, 0. )) ;
1085 
1086     unsigned type = CSG_DISCONTIGUOUS ; // useful during dev to see constituents
1087     //unsigned type = CSG_CONTIGUOUS ; 
1088     return makeList( label, type, leaves, &tran ); 
1089 }
1090 
1091 
1092 /**
1093 CSGMaker::makeBooleanSeptuplet
1094 ----------------------------------
1095 
1096 
1097                         1:t
1098 
1099              10:l                   11:r
1100  
1101        100:ll    101:lr       110:rl     111:rr
1102 
1103 **/
1104 
1105 CSGSolid* CSGMaker::makeBooleanSeptuplet( 
1106     const char* label, 
1107     const CSGNode& top, 
1108     const CSGNode& l, 
1109     const CSGNode& r, 
1110     const CSGNode& ll, 
1111     const CSGNode& lr, 
1112     const CSGNode& rl, 
1113     const CSGNode& rr, 
1114     const int meshIdx ) 
1115 {
1116     unsigned numPrim = 1 ; 
1117     CSGSolid* so = fd->addSolid(numPrim, label);
1118 
1119     unsigned numNode = 7 ; 
1120     int nodeOffset_ = -1 ; 
1121     CSGPrim* p = fd->addPrim(numNode, nodeOffset_ ); 
1122     if(meshIdx > -1) p->setMeshIdx(meshIdx); 
1123 
1124     std::vector<CSGNode> nn = {top, l, r, ll, lr, rl, rr } ; 
1125     assert( nn.size() == numNode ); 
1126 
1127     CSGNode* tptr = nullptr ; 
1128     AABB bb = {} ;
1129     for(unsigned i=0 ; i < numNode ; i++ )
1130     {
1131         const CSGNode& n = nn[i] ; 
1132         CSGNode* nptr = fd->addNode(n); 
1133         if(i == 0) tptr = nptr ;  
1134 
1135         if( n.is_primitive() && !n.is_zero() && !n.is_complement() )
1136         {
1137             bb.include_aabb( n.AABB() );   // naive bbox combination : overlarge bbox
1138         }
1139     }
1140     p->setAABB( bb.data() );  
1141 
1142     so->center_extent = bb.center_extent()  ; 
1143 
1144     // setting transform as otherise loading foundry fails for lack of non-optional tran array 
1145     //const Tran<double>* tran_identity = Tran<double>::make_identity(); 
1146     unsigned transform_idx = 1 + fd->addTran();   // 1-based idx, 0 meaning None
1147     tptr->setTransform(transform_idx); 
1148 
1149     //LOG(LEVEL) << "so.label " << so->getLabel() << " so.center_extent " << so->center_extent ; 
1150     return so ; 
1151 }
1152 
1153 
1154 CSGSolid* CSGMaker::makeDifferenceCylinder( const char* label, float rmax, float rmin, float z1, float z2, float z_inner_factor   )
1155 {
1156     assert( rmax > rmin ); 
1157     assert( z2 > z1 ); 
1158     CSGNode outer = CSGNode::Cylinder( rmax, z1, z2 ); 
1159     CSGNode inner = CSGNode::Cylinder( rmin, z1*z_inner_factor, z2*z_inner_factor ); 
1160     return makeBooleanTriplet(label, CSG_DIFFERENCE, outer, inner ); 
1161 }
1162 
1163 /**
1164 CSGMaker::makeBoxSubSubCylinder
1165 ---------------------------------
1166 
1167          
1168                    t:di
1169           
1170           l:bx             r:di 
1171  
1172        ll:ze  lr:ze    rl:cy    rr:cy
1173               
1174  
1175 **/
1176 
1177 
1178 CSGSolid* CSGMaker::makeBoxSubSubCylinder( const char* label, float fullside, float rmax, float rmin, float z1, float z2, float z_inner_factor   )
1179 {
1180     CSGNode t = CSGNode::BooleanOperator(CSG_DIFFERENCE, -1); 
1181     CSGNode l = CSGNode::Box3(fullside) ;
1182     CSGNode r = CSGNode::BooleanOperator(CSG_DIFFERENCE, -1); 
1183     CSGNode ll = CSGNode::Zero(); 
1184     CSGNode lr = CSGNode::Zero(); 
1185     CSGNode rl = CSGNode::Cylinder( rmax, z1, z2 ); 
1186     CSGNode rr = CSGNode::Cylinder( rmin, z1*z_inner_factor, z2*z_inner_factor ); 
1187     int meshIdx = -1 ;  
1188     return makeBooleanSeptuplet(label, t, l, r, ll, lr, rl, rr, meshIdx );  
1189 }
1190 
1191 
1192 
1193 
1194 
1195 CSGSolid* CSGMaker::makeUnionBoxSphere( const char* label, float radius, float fullside ){
1196     return makeBooleanBoxSphere(label, CSG_UNION, radius, fullside, UBSP_MIDX ); 
1197 }
1198 CSGSolid* CSGMaker::makeIntersectionBoxSphere( const char* label, float radius, float fullside ){
1199     return makeBooleanBoxSphere(label, CSG_INTERSECTION, radius, fullside, IBSP_MIDX ); 
1200 }
1201 CSGSolid* CSGMaker::makeDifferenceBoxSphere( const char* label, float radius, float fullside ){
1202     return makeBooleanBoxSphere(label, CSG_DIFFERENCE, radius, fullside, DBSP_MIDX ); 
1203 }
1204 
1205 
1206 
1207 
1208 
1209 CSGSolid* CSGMaker::makeSphere(const char* label, float radius)
1210 {
1211     CSGNode nd = CSGNode::Sphere(radius); 
1212     return makeSolid11(label, nd, nullptr, SPHE_MIDX ); 
1213 }
1214 
1215 /**
1216 CSGMaker::makeEllipsoid
1217 --------------------------
1218 
1219 Hmm adding the transform to CSGFoundry before the prim gets added is problematic
1220 for CSGCloneTest as transfrom offsets get captured at prim creation. 
1221 
1222 **/
1223 
1224 CSGSolid* CSGMaker::makeEllipsoid(  const char* label, float rx, float ry, float rz )
1225 {
1226     CSGNode nd = CSGNode::Sphere(rx);
1227 
1228     double dx = double(rx) ; 
1229     double dy = double(ry) ; 
1230     double dz = double(rz) ; 
1231  
1232     double sx = double(1.) ; 
1233     double sy = dy/dx ; 
1234     double sz = dz/dx ; 
1235 
1236     const Tran<double>* tr = Tran<double>::make_scale(sx, sy, sz ); 
1237 
1238     return makeSolid11(label, nd, nullptr, ELLI_MIDX, tr ); 
1239 }
1240 
1241 
1242 CSGSolid* CSGMaker::makeRotatedCylinder(const char* label, float px, float py, float radius, float z1, float z2, float ax, float ay, float az, float angle_deg )
1243 {
1244     assert( px == 0.f ); // not supported anymore  
1245     assert( py == 0.f ); 
1246 
1247     CSGNode nd = CSGNode::Cylinder( radius, z1, z2 ); 
1248     const Tran<double>* tr = Tran<double>::make_rotate(ax, ay, az, angle_deg ); 
1249     return makeSolid11(label, nd, nullptr, RCYL_MIDX, tr  ); 
1250 }
1251 
1252 
1253 CSGSolid* CSGMaker::makeInfCylinder(const char* label, float radius, float hz )
1254 {
1255     CSGNode nd = CSGNode::InfCylinder( radius, hz ); 
1256     return makeSolid11(label, nd, nullptr, ICYL_MIDX ); 
1257 }
1258 
1259 CSGSolid* CSGMaker::makeInfPhiCut(const char* label, float startPhi_pi, float deltaPhi_pi )
1260 {
1261     CSGNode nd = CSGNode::InfPhiCut(startPhi_pi, deltaPhi_pi ); 
1262     return makeSolid11(label, nd, nullptr, IPHI_MIDX ); 
1263 }
1264 
1265 
1266 CSGSolid* CSGMaker::makeInfThetaCut(const char* label, float startTheta_pi, float deltaTheta_pi )
1267 {
1268     CSGNode nd = CSGNode::InfThetaCut(startTheta_pi, deltaTheta_pi ); 
1269     return makeSolid11(label, nd, nullptr, ITHE_MIDX ); 
1270 }
1271 CSGSolid* CSGMaker::makeInfThetaCutL(const char* label, float startTheta_pi, float deltaTheta_pi )
1272 {
1273     CSGNode nd = CSGNode::InfThetaCut(startTheta_pi, deltaTheta_pi ); 
1274     return makeSolid11(label, nd, nullptr, ITHL_MIDX ); 
1275 }
1276 
1277 
1278 
1279 
1280 
1281 CSGSolid* CSGMaker::makeZSphere(const char* label, float radius, float z1, float z2)
1282 {
1283     CSGNode nd = CSGNode::ZSphere(radius, z1, z2); 
1284     return makeSolid11(label, nd, nullptr, ZSPH_MIDX ); 
1285 }
1286 
1287 CSGSolid* CSGMaker::makeCone(const char* label, float r1, float z1, float r2, float z2)
1288 {
1289     CSGNode nd = CSGNode::Cone(r1, z1, r2, z2 ); 
1290     return makeSolid11(label, nd, nullptr, CONE_MIDX ); 
1291 }
1292 
1293 CSGSolid* CSGMaker::makeHyperboloid(const char* label, float r0, float zf, float z1, float z2)
1294 {
1295     CSGNode nd = CSGNode::Hyperboloid( r0, zf, z1, z2 ); 
1296     return makeSolid11(label, nd, nullptr, HYPE_MIDX ); 
1297 }
1298 
1299 CSGSolid* CSGMaker::makeBox3(const char* label, float fx, float fy, float fz )
1300 {
1301     CSGNode nd = CSGNode::Box3(fx, fy, fz); 
1302     return makeSolid11(label, nd, nullptr, BOX3_MIDX ); 
1303 }
1304 
1305 CSGSolid* CSGMaker::makePlane(const char* label, float nx, float ny, float nz, float d)
1306 {
1307     CSGNode nd = CSGNode::Plane(nx, ny, nz, d ); 
1308     return makeSolid11(label, nd, nullptr, PLAN_MIDX ); 
1309 }
1310 
1311 CSGSolid* CSGMaker::makeSlab(const char* label, float nx, float ny, float nz, float d1, float d2 )
1312 {
1313     CSGNode nd = CSGNode::Slab( nx, ny, nz, d1, d1 ); 
1314     return makeSolid11(label, nd, nullptr, SLAB_MIDX ); 
1315 }
1316 
1317 CSGSolid* CSGMaker::makeCylinder(const char* label, float radius, float z1, float z2)
1318 {
1319     CSGNode nd = CSGNode::Cylinder( radius, z1, z2 ); 
1320     return makeSolid11(label, nd, nullptr, CYLI_MIDX ); 
1321 }
1322 
1323 CSGSolid* CSGMaker::makeOldCylinder(const char* label, float radius, float z1, float z2)
1324 {
1325     CSGNode nd = CSGNode::OldCylinder( radius, z1, z2 ); 
1326     return makeSolid11(label, nd, nullptr, OCYL_MIDX ); 
1327 }
1328 
1329 
1330 CSGSolid* CSGMaker::makeDisc(const char* label, float px, float py, float ir, float r, float z1, float z2)
1331 {
1332     CSGNode nd = CSGNode::Disc(px, py, ir, r, z1, z2 ); 
1333     return makeSolid11(label, nd, nullptr, DISC_MIDX ); 
1334 }
1335 
1336 
1337 float4 CSGMaker::TriPlane( const std::vector<float3>& v, unsigned i, unsigned j, unsigned k )  // static 
1338 {
1339     // normal for plane through v[i] v[j] v[k]
1340     float3 ij = v[j] - v[i] ; 
1341     float3 ik = v[k] - v[i] ; 
1342     float3 n = normalize(cross(ij, ik )) ;
1343     float di = dot( n, v[i] ) ;
1344     //float dj = dot( n, v[j] ) ;
1345     //float dk = dot( n, v[k] ) ;
1346     //LOG(info) << " di " << di << " dj " << dj << " dk " << dk << " n (" << n.x << "," << n.y << "," << n.z << ")" ; 
1347     float4 plane = make_float4( n, di ) ; 
1348     return plane ;  
1349 }
1350 
1351 CSGSolid* CSGMaker::makeConvexPolyhedronCube(const char* label, float extent)
1352 {
1353     float hx = extent ; 
1354     float hy = extent/2.f ; 
1355     float hz = extent/3.f ; 
1356 
1357     std::vector<float4> pl ; 
1358     pl.push_back( make_float4(  1.f,  0.f,  0.f, hx ) ); 
1359     pl.push_back( make_float4( -1.f,  0.f,  0.f, hx ) ); 
1360     pl.push_back( make_float4(  0.f,  1.f,  0.f, hy ) ); 
1361     pl.push_back( make_float4(  0.f, -1.f,  0.f, hy ) ); 
1362     pl.push_back( make_float4(  0.f,  0.f,  1.f, hz ) ); 
1363     pl.push_back( make_float4(  0.f,  0.f, -1.f, hz ) );
1364 
1365     CSGNode nd = {} ;
1366     nd.setAABB(-hx, -hy, -hz, hx, hy, hz); 
1367     return makeSolid11(label, nd, &pl, VCUB_MIDX ); 
1368 }
1369 
1370 
1371 /*  
1372      https://en.wikipedia.org/wiki/Tetrahedron
1373 
1374        0:(1,1,1)
1375        1:(1,−1,−1)
1376        2:(−1,1,−1) 
1377        3:(−1,−1,1)
1378 
1379                               (1,1,1)
1380                  +-----------0
1381                 /|          /| 
1382      (-1,-1,1) / |         / |
1383               3-----------+  |
1384               |  |        |  |
1385               |  |        |  |
1386    (-1,1,-1)..|..2--------|--+
1387               | /         | /
1388               |/          |/
1389               +-----------1
1390                           (1,-1,-1)      
1391 
1392           Faces (right-hand-rule oriented outwards normals)
1393                 0-1-2
1394                 1-3-2
1395                 3-0-2
1396                 0-3-1
1397 
1398          z  y
1399          | /
1400          |/
1401          +---> x
1402 */
1403 
1404 CSGSolid* CSGMaker::makeConvexPolyhedronTetrahedron(const char* label, float extent)
1405 {
1406     //extent = 100.f*sqrt(3); 
1407     float s = extent ; 
1408 
1409     std::vector<float3> vtx ; 
1410     vtx.push_back(make_float3( s, s, s));  
1411     vtx.push_back(make_float3( s,-s,-s)); 
1412     vtx.push_back(make_float3(-s, s,-s)); 
1413     vtx.push_back(make_float3(-s,-s, s)); 
1414 
1415     std::vector<float4> pl ; 
1416     pl.push_back(TriPlane(vtx, 0, 1, 2)) ;  
1417     pl.push_back(TriPlane(vtx, 1, 3, 2)) ;  
1418     pl.push_back(TriPlane(vtx, 3, 0, 2)) ;  
1419     pl.push_back(TriPlane(vtx, 0, 3, 1)) ;  
1420 
1421     //for(unsigned i=0 ; i < pl.size() ; i++) LOG(info) << " pl (" << pl[i].x << "," << pl[i].y << "," << pl[i].z << "," << pl[i].w << ") " ;
1422  
1423     CSGNode nd = {} ;
1424     nd.setAABB(extent); 
1425     return makeSolid11(label, nd, &pl, VTET_MIDX ); 
1426 }
1427 
1428 
1429 
1430 /**
1431 CSGMaker::MakeGeom
1432 ----------------------
1433 
1434 Intended for creation of small CSGFoundry test geometries that are entirely created by this method.
1435 
1436 Formerly was CSGFoundry::MakeGeom
1437 
1438 **/
1439 
1440 CSGFoundry*  CSGMaker::MakeGeom(const char* geom) // static
1441 {
1442     CSGFoundry* fd = new CSGFoundry();  
1443     CSGMaker* mk = fd->maker ;
1444     CSGSolid* so = mk->make( geom );
1445     fd->setGeom(geom);  
1446 
1447     fd->addTranPlaceholder();  
1448     fd->addInstancePlaceholder(); 
1449 
1450     // avoid tripping some checks 
1451     fd->addMeshName(geom);   
1452     fd->addSolidMMLabel(geom);  
1453     fd->setMeta<std::string>("source", "CSGFoundry::MakeGeom" ); 
1454 
1455     assert( so ); 
1456 
1457     LOG(info) << " so " << so ;
1458     LOG(info) << " so.desc " << so->desc() ;
1459     LOG(info) << " fd.desc " << fd->desc() ;
1460 
1461     return fd ; 
1462 }
1463 /**
1464 CSGMaker::MakeDemo
1465 ---------------------
1466 
1467 Formerly was CSGFoundry::MakeDemo
1468 
1469 **/
1470 
1471 CSGFoundry*  CSGMaker::MakeDemo()
1472 {
1473     CSGFoundry* fd = new CSGFoundry();
1474     fd->makeDemoSolids(); 
1475     return fd ; 
1476 }
1477 
1478 
1479 
1480 /**
1481 CSGMaker::LoadGeom (formerly CSGFoundry::LoadGeom)
1482 ----------------------------------------------------
1483 
1484 HMM: is there reason for this anymore : simpler
1485 to treat full geometries and small geometries just the same 
1486 from the point of view of loading. 
1487 
1488 
1489 
1490 CSGFoundry* CSGMaker::LoadGeom(const char* geom) // static
1491 {
1492     if(geom == nullptr) geom = ssys::getenvvar("GEOM", "GeneralSphereDEV") ; 
1493 
1494     //CSGFoundry* fd = new CSGFoundry();  
1495     //fd->setGeom(geom); 
1496     //fd->load(); 
1497 
1498     CSGFoundry* fd = CSGFoundry::Load();  
1499     
1500     const char* meta = fd->meta.empty() ? nullptr : fd->meta.c_str();  
1501 
1502     LOG(LEVEL) 
1503        << " geom " << geom 
1504        << " loaddir " << fd->loaddir 
1505        << ( meta ? "\n" : "" )
1506        << ( meta ? meta : "-" )
1507        ; 
1508 
1509     return fd ; 
1510 } 
1511 
1512 **/
1513