diff --git a/DDCAD/include/DDCAD/ASSIMPReader.h b/DDCAD/include/DDCAD/ASSIMPReader.h index 59d74f9cdc9490af0303f35b1a1f0b7228939188..80fdf5ada35195e4010dd9446fcf3f5e6eecb0e0 100644 --- a/DDCAD/include/DDCAD/ASSIMPReader.h +++ b/DDCAD/include/DDCAD/ASSIMPReader.h @@ -24,16 +24,30 @@ namespace dd4hep { /// Namespace for implementation details of the AIDA detector description toolkit namespace cad { + /// Reader class to input geometry shapes from CAD files + /** + * As a helper the ASSIMP library is used to interprete the + * CAD formats. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DDCAD + */ class ASSIMPReader : public InputReader { public: using InputReader::InputReader; + /// Default destructor virtual ~ASSIMPReader() = default; + /// Read input file virtual std::vector<std::unique_ptr<TGeoTessellated> > - read(const std::string& source, double unit_Length) const override; + readShapes(const std::string& source, double unit_Length) const override; + + /// Read input file and create a volume-set + virtual std::vector<std::unique_ptr<TGeoVolume> > + readVolumes(const std::string& source, double unit_length) const override; }; - } /* End namespace cad */ } /* End namespace dd4hep */ #endif // DDCAD_ASSIMPREADER_H diff --git a/DDCAD/include/DDCAD/ASSIMPWriter.h b/DDCAD/include/DDCAD/ASSIMPWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..4d08da066363892e73b186d089af652b66976b7d --- /dev/null +++ b/DDCAD/include/DDCAD/ASSIMPWriter.h @@ -0,0 +1,51 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDCAD_ASSIMPWRITER_H +#define DDCAD_ASSIMPWRITER_H + +/// Framework include files +#include <DDCAD/OutputWriter.h> + +/// C/C++ include files + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Namespace for implementation details of the AIDA detector description toolkit + namespace cad { + + /// Writer class to output geometry shapes from CAD files + /** + * As a helper the ASSIMP library is used to interprete the + * CAD formats. + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DDCAD + */ + class ASSIMPWriter : public OutputWriter { + public: + using OutputWriter::OutputWriter; + /// Default destructor + virtual ~ASSIMPWriter() = default; + /// Write output file + virtual int write(const std::string& output_file, + const std::string& output_type, + const VolumePlacements& places, + bool recursive, + double unit_scale = 1.0) const override; + }; + + } /* End namespace cad */ +} /* End namespace dd4hep */ +#endif // DDCAD_ASSIMPWRITER_H diff --git a/DDCAD/include/DDCAD/InputReader.h b/DDCAD/include/DDCAD/InputReader.h index 69ebd1eefadf55bd181c0f3b6e77f6db691c3994..c68d544538a3ff293f3be7fc9f66d0a04ec2cfcb 100644 --- a/DDCAD/include/DDCAD/InputReader.h +++ b/DDCAD/include/DDCAD/InputReader.h @@ -16,6 +16,8 @@ // Framework include files #include <DD4hep/config.h> +/// ROOT include files +#include <TGeoVolume.h> #include <TGeoTessellated.h> /// C/C++ include files @@ -26,18 +28,38 @@ /// Namespace for the AIDA detector description toolkit namespace dd4hep { + /// Forward declarations + class Detector; + /// Namespace for implementation details of the AIDA detector description toolkit namespace cad { + /// Interface of the reader class to input geometry shapes from CAD files + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DDCAD + */ class InputReader { + public: + /// Reference to the detector object + Detector& detector; + public: /// Default constructor - InputReader(); + InputReader(Detector& detector); + /// Default destructor virtual ~InputReader(); + /// Read input file virtual std::vector<std::unique_ptr<TGeoTessellated> > - read(const std::string& source, double unit_length) const = 0; + readShapes(const std::string& source, double unit_length) const = 0; + + /// Read input file and create a volume-set + virtual std::vector<std::unique_ptr<TGeoVolume> > + readVolumes(const std::string& source, double unit_length) const = 0; }; } /* End namespace cad */ diff --git a/DDCAD/include/DDCAD/OutputWriter.h b/DDCAD/include/DDCAD/OutputWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..2f98ca215adc61e65273196f9c2e9576c01e4c6b --- /dev/null +++ b/DDCAD/include/DDCAD/OutputWriter.h @@ -0,0 +1,69 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== +#ifndef DDCAD_INPUTWRITER_H +#define DDCAD_INPUTWRITER_H + +// Framework include files +#include <DD4hep/config.h> +#include <DD4hep/Volumes.h> + +/// C/C++ include files +#include <string> +#include <vector> +#include <memory> + +/// Namespace for the AIDA detector description toolkit +namespace dd4hep { + + /// Forward declarations + class Detector; + + /// Namespace for implementation details of the AIDA detector description toolkit + namespace cad { + + /// Interface of the writer class to output geometry shapes from CAD files + /** + * + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_DDCAD + */ + class OutputWriter { + public: + enum output_flags { + EXPORT_POINT_CLOUDS = 1 << 1, + LAST = 0 + }; + public: + /// Reference to the detector object + Detector& detector; + /// Output configuration flags + unsigned long flags { 0 }; + + public: + typedef std::vector<PlacedVolume> VolumePlacements; + /// Default constructor + OutputWriter(Detector& detector); + /// Default destructor + virtual ~OutputWriter(); + /// Write output file + virtual int write(const std::string& output_file, + const std::string& output_type, + const VolumePlacements& places, + bool recursive, + double unit_scale = 1.0) const = 0; + }; + + } /* End namespace cad */ +} /* End namespace dd4hep */ +#endif // DDCAD_INPUTWRITER_H diff --git a/DDCAD/src/ASSIMPReader.cpp b/DDCAD/src/ASSIMPReader.cpp index 4b7ffd606d8b780bf27e10089f7639a9b4b2ba42..d4793bf20de8a5d8fcfbcc8b65b11c2a3a1c7ace 100644 --- a/DDCAD/src/ASSIMPReader.cpp +++ b/DDCAD/src/ASSIMPReader.cpp @@ -14,6 +14,7 @@ /// Framework include files #include <DD4hep/Shapes.h> #include <DD4hep/Printout.h> +#include <DD4hep/Detector.h> #include <DDCAD/ASSIMPReader.h> /// Open Asset Importer Library @@ -22,15 +23,16 @@ #include "assimp/scene.h" #include "assimp/postprocess.h" -using namespace std; using namespace dd4hep; using namespace dd4hep::cad; /// Read input file -vector<unique_ptr<TGeoTessellated> > -ASSIMPReader::read(const string& source, double unit_length) const { - vector<unique_ptr<TGeoTessellated> > result; - unique_ptr<Assimp::Importer> importer = make_unique<Assimp::Importer>(); +std::vector<std::unique_ptr<TGeoTessellated> > +ASSIMPReader::readShapes(const std::string& source, double unit_length) const +{ + typedef TessellatedSolid::Vertex Vertex; + std::vector<std::unique_ptr<TGeoTessellated> > result; + std::unique_ptr<Assimp::Importer> importer = std::make_unique<Assimp::Importer>(); int flags = aiProcess_Triangulate|aiProcess_JoinIdenticalVertices|aiProcess_CalcTangentSpace; auto scene = importer->ReadFile( source.c_str(), flags); if ( !scene ) { @@ -46,23 +48,102 @@ ASSIMPReader::read(const string& source, double unit_length) const { for(unsigned int i=0; i < mesh->mNumFaces; i++) { const aiFace& face = mesh->mFaces[i]; const unsigned int* idx = face.mIndices; - Tessellated::Vertex_t a(v[idx[0]].x*unit, v[idx[0]].y*unit, v[idx[0]].z*unit); - Tessellated::Vertex_t b(v[idx[1]].x*unit, v[idx[1]].y*unit, v[idx[1]].z*unit); - Tessellated::Vertex_t c(v[idx[2]].x*unit, v[idx[2]].y*unit, v[idx[2]].z*unit); + Vertex a(v[idx[0]].x*unit, v[idx[0]].y*unit, v[idx[0]].z*unit); + Vertex b(v[idx[1]].x*unit, v[idx[1]].y*unit, v[idx[1]].z*unit); + Vertex c(v[idx[2]].x*unit, v[idx[2]].y*unit, v[idx[2]].z*unit); + shape->AddFacet(a,b,c); + } + if ( shape->GetNfacets() > 2 ) { + result.emplace_back(std::unique_ptr<TGeoTessellated>(shape.ptr())); + continue; + } + delete shape.ptr(); + } + } + printout(ALWAYS,"ASSIMPReader","+++ Read %ld meshes from %s", + result.size(), source.c_str()); + return result; +} + +/// Read input file and create a volume-set +std::vector<std::unique_ptr<TGeoVolume> > +ASSIMPReader::readVolumes(const std::string& source, double unit_length) const +{ + typedef TessellatedSolid::Vertex Vertex; + std::vector<std::unique_ptr<TGeoVolume> > result; + std::unique_ptr<Assimp::Importer> importer = std::make_unique<Assimp::Importer>(); + int flags = aiProcess_Triangulate|aiProcess_JoinIdenticalVertices|aiProcess_CalcTangentSpace; + auto scene = importer->ReadFile( source.c_str(), flags); + char text[128]; + + if ( !scene ) { + except("ASSIMPReader","+++ FileNotFound: %s",source.c_str()); + } + double unit = unit_length; + for (unsigned int index = 0; index < scene->mNumMeshes; index++) { + aiMesh* mesh = scene->mMeshes[index]; + if ( mesh->mNumFaces > 0 ) { + auto name = mesh->mName.C_Str(); + TessellatedSolid shape(name, mesh->mNumFaces); + const aiVector3D* v = mesh->mVertices; + for(unsigned int i=0; i < mesh->mNumFaces; i++) { + const aiFace& face = mesh->mFaces[i]; + const unsigned int* idx = face.mIndices; + Vertex a(v[idx[0]].x*unit, v[idx[0]].y*unit, v[idx[0]].z*unit); + Vertex b(v[idx[1]].x*unit, v[idx[1]].y*unit, v[idx[1]].z*unit); + Vertex c(v[idx[2]].x*unit, v[idx[2]].y*unit, v[idx[2]].z*unit); shape->AddFacet(a,b,c); -#if 0 - if ( scene->HasMaterials() ) { - const aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex]; - printout(INFO,"ASSIMPReader","+++ Material: %p",mat); - } -#endif } if ( shape->GetNfacets() > 2 ) { - result.emplace_back(unique_ptr<TGeoTessellated>(shape.ptr())); + std::string nam; + Material mat; + VisAttr vis; + if ( scene->HasMaterials() ) { + aiMaterial* ai_mat = scene->mMaterials[mesh->mMaterialIndex]; + nam = ai_mat->GetName().C_Str(); + mat = detector.material(nam); + } + if ( !mat.isValid() ) { + printout(ERROR, "ASSIMPReader", + "+++ %s: No material named '%s' FOUND. Will use Air. [Missing material]", + text, nam.c_str()); + mat = detector.air(); + } + ::snprintf(text,sizeof(text),"tessellated_%ld", result.size()); + text[sizeof(text)-1] = 0; + Volume vol(text, Solid(shape.ptr()), mat); + if ( mesh->HasVertexColors(0) ) { + const aiColor4D* col = mesh->mColors[0]; + if ( col ) { + for( const auto& _v : detector.visAttributes() ) { + float a, r, g, b, eps = 0.05; + VisAttr(_v.second).argb(a, r, g, b); + if( std::abs(col->a-a) < eps && std::abs(col->r-r) < eps && + std::abs(col->g-g) < eps && std::abs(col->b-b) < eps ) { + vis = _v.second; + break; + } + } + if ( !vis.isValid() ) { + ::snprintf(text,sizeof(text),"vis_tessellated_%p", (void*)vol.ptr()); + text[sizeof(text)-1] = 0; + vis = VisAttr(text); + vis.setColor(col->a,col->r,col->g,col->b); + detector.add(vis); + } + vol.setVisAttributes(vis); + } + } + printout(INFO,"ASSIMPReader", + "+++ %-17s Material: %-16s Viualization: %s", + vol.name(), mat.name(), vis.isValid() ? vis.name() : "NONE"); + result.emplace_back(std::unique_ptr<TGeoVolume>(vol.ptr())); continue; } delete shape.ptr(); } } + printout(ALWAYS,"ASSIMPReader","+++ Read %ld meshes from %s", + result.size(), source.c_str()); return result; } diff --git a/DDCAD/src/ASSIMPWriter.cpp b/DDCAD/src/ASSIMPWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a01f5cb755b4acf04fed367aab007e961e7004df --- /dev/null +++ b/DDCAD/src/ASSIMPWriter.cpp @@ -0,0 +1,375 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + +/// Framework include files +#include <DD4hep/Shapes.h> +#include <DD4hep/Objects.h> +#include <DD4hep/Printout.h> +#include <DDCAD/ASSIMPWriter.h> + +/// Open Asset Importer Library +#include "assimp/postprocess.h" +#include "assimp/Exporter.hpp" +#include "assimp/scene.h" + +#include <TBuffer3D.h> +#include <TGeoMatrix.h> + +/// C/C++ include files +#include <set> + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::cad; + +namespace { + + void _collect(std::vector<std::pair<PlacedVolume,TGeoHMatrix*> >& cont, + bool recursive, const TGeoHMatrix& to_global, PlacedVolume pv) + { + Volume v = pv.volume(); + for(Int_t i=0; i<v->GetNdaughters(); ++i) { + PlacedVolume p = v->GetNode(i); + Solid sol = p.volume().solid(); + // TessellatedSolid sol = p.volume().solid(); + // if ( sol.isValid() ) cont.push_back(p); + unique_ptr<TGeoHMatrix> mother(new TGeoHMatrix(to_global)); + mother->Multiply(p->GetMatrix()); + + if ( sol->IsA() != TGeoShapeAssembly::Class() ) + cont.push_back(make_pair(p, mother.get())); + if ( recursive ) + _collect(cont, recursive, *mother, p); + if ( sol->IsA() != TGeoShapeAssembly::Class() ) + mother.release(); + } + } + struct vertex{ double x,y,z; + vertex() = default; + vertex(const vertex& copy) = default; + vertex(double vx, double vy, double vz) : x(vx), y(vy), z(vz) {} + vertex(const Tessellated::Vertex_t& v) : x(v.x()), y(v.y()), z(v.z()) {} + vertex& operator=(const vertex& v) = default; + vertex& operator=(const Tessellated::Vertex_t& v) + { x = v.x(); y = v.y(); z = v.z(); return *this; } + operator Tessellated::Vertex_t () const + { return Tessellated::Vertex_t(x,y,z); } + }; + vertex operator-(const vertex& v1, const vertex& v2) + { return vertex(v1.x-v2.x, v1.y-v2.y, v1.z-v2.z); } + vertex operator+(const vertex& v1, const vertex& v2) + { return vertex(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z); } + +#if 0 + num_facet = tes->GetNfacets(); + int *nn = new int[num_facet]; + bool* flipped = new bool[num_facet]; + for( i=0; i < num_facet; ++i ) + flipped[i] = false, nn[0] = 0; + for( i=0; i < num_facet; ++i ) { + for( size_t j= i+1; j < num_facet; ++j) { + bool isneighbour = tes->GetFacet(i).IsNeighbour(tes->GetFacet(j), flipped[j]); + if ( isneighbour ) { + if ( flipped[i] ) flipped[j] = !flipped[j]; + ++nn[i]; + ++nn[j]; + if ( nn[i] == tes->GetFacet(i).GetNvert() ) + break; + } + } + } + for( i=0; i < num_facet; ++i ) { + if ( flipped[i] ) { + const_cast<TGeoFacet*>(&tes->GetFacet(i))->Flip(); + } + } + delete [] flipped; + delete [] nn; +#endif +#if 0 + template <typename TGBinder> + TPlane3 compute_plane(const TGBinder &poly) { + TPoint3 plast(poly[poly.Size()-1]); + TPoint3 pivot; + TVector3 edge; + Int_t j; + for (j = 0; j < poly.Size(); j++) { + pivot = poly[j]; + edge = pivot - plast; + if (!edge.FuzzyZero()) break; + } + for (; j < poly.Size(); j++) { + TVector3 v2 = poly[j] - pivot; + TVector3 v3 = edge.Cross(v2); + if (!v3.FuzzyZero()) + return TPlane3(v3,pivot); + } + + return TPlane3(); + } + + + /* ------------------------------------------------------------ + // Convert quadri-linear facet to 2 tri-linear facets + // + // f1 +---------------+ v2/v3: f0 + // / / + // / / + // / / + // +---------------+ + // v0 v1 v2/v3 + // --------------------------------------------------------- */ + int num_points[3]; + pol_t* pol = (pol_t*)q; + int s1 = pol->segs[0], s2 = pol->segs[1]; + int ends[4] = {segs[s1]._1,segs[s1]._2,segs[s2]._1,segs[s2]._2}; + + q += (2+pol->n); + if (ends[0] == ends[2]) { + numPnts[0] = ends[1]; + numPnts[1] = ends[0]; + numPnts[2] = ends[3]; + } + else if (ends[0] == ends[3]) { + numPnts[0] = ends[1]; + numPnts[1] = ends[0]; + numPnts[2] = ends[2]; + } + else if (ends[1] == ends[2]) { + numPnts[0] = ends[0]; + numPnts[1] = ends[1]; + numPnts[2] = ends[3]; + } + else { + numPnts[0] = ends[0]; + numPnts[1] = ends[1]; + numPnts[2] = ends[2]; + } + Int_t lastAdded = numPnts[2]; + for( int j=pol->n; j != 2; --j ) { + ends[0] = segs[pol->segs[j]]._1; + ends[1] = segs[pol->segs[j]]._2; + if (ends[0] == lastAdded) { + lastAdded = ends[1]; + } + else { + lastAdded = ends[0]; + } + } + + +#endif +} + +/// Write output file +int ASSIMPWriter::write(const std::string& file_name, + const std::string& file_type, + const VolumePlacements& places, + bool recursive, + double unit_scale) const +{ + std::vector<std::pair<PlacedVolume,TGeoHMatrix*> > placements; + vector<Material> materials; + TGeoHMatrix toGlobal; + + for( auto pv : places ) + _collect(placements, recursive, toGlobal, pv); + + size_t num_mesh = placements.size(); + + aiScene scene; + scene.mNumMaterials = 0; + scene.mNumMeshes = 0; + scene.mMeshes = new aiMesh* [num_mesh]; + scene.mMaterials = new aiMaterial* [num_mesh]; + + aiNode *root = new aiNode(); + scene.mRootNode = root; + root->mName.Set("<STL>"); + root->mNumMeshes = 0; + root->mNumChildren = 0; + root->mChildren = new aiNode* [num_mesh]; + root->mMeshes = 0;//new unsigned int[root->mNumMeshes]; + + for( size_t imesh=0; imesh < num_mesh; ++imesh ) { + unique_ptr<TGeoHMatrix> trafo(placements[imesh].second); + PlacedVolume pv = placements[imesh].first; + Volume v = pv.volume(); + Material m = v.material(); + TessellatedSolid tes = v.solid(); + aiString node_name(v.name()); + + // + unique_ptr<TGeoTessellated> buf; + if ( !tes.isValid() ) { + typedef vertex vtx_t; + unique_ptr<TBuffer3D> buf3D(v.solid()->MakeBuffer3D()); + struct pol_t { int c, n; int segs[1]; } *pol; + struct seg_t { int c, _1, _2; }; + const seg_t* segs = (seg_t*)buf3D->fSegs; + const vtx_t* vtcs = (vtx_t*)buf3D->fPnts; + size_t i, num_facet = 0; + const Int_t* q; + + for( i=0, q=buf3D->fPols; i<buf3D->NbPols(); ++i, q += (2+pol->n)) { + pol = (pol_t*)q; + for( int j=0; j < pol->n-1; ++j ) num_facet += 2; + } + + buf = make_unique<TGeoTessellated>(v.name(), num_facet); + tes = buf.get(); + q = buf3D->fPols; + for( i=0, q=buf3D->fPols; i<buf3D->NbPols(); ++i) { + pol_t* pol = (pol_t*)q; + q += (2+pol->n); + for( int j=0; j < pol->n; j += 2 ) { + /* ------------------------------------------------------------ + // Convert quadri-linear facet to 2 tri-linear facets + // + // f1 +---------------+ v2/v3: f0 + // / / + // / / + // / / + // +---------------+ + // v0 v1 v2/v3 + // --------------------------------------------------------- */ + const int s1 = pol->segs[j], s2 = pol->segs[(j+1)%pol->n]; + const int s[] = { segs[s1]._1, segs[s1]._2, segs[s2]._1, segs[s2]._2 }; + const vtx_t& v0 = vtcs[s[0]], &v1=vtcs[s[1]], &v2=vtcs[s[2]], &v3=vtcs[s[3]]; + + if ( s[0] == s[2] ) { // Points are ( s[1], s[0], s[3] ) + tes->AddFacet(v1, v0, v3); + } + else if ( s[0] == s[3] ) { // Points are ( s[1], s[0], s[2] ) + tes->AddFacet(v1, v0, v2); + } + else if ( s[1] == s[2] ) { // Points are ( s[0], s[1], s[3] ) + tes->AddFacet(v0, v1, v3); + } + else { // Points are ( s[0], s[1], s[2] ) + tes->AddFacet(v0, v1, v2); + } + } + } + } + if ( tes->GetNfacets() == 0 ) { + continue; + } + + size_t num_vert = 0; + for( long j=0, n=tes->GetNfacets(); j < n; ++j ) + num_vert += tes->GetFacet(j).GetNvert(); + + size_t index = std::numeric_limits<size_t>::max(); + for( size_t j=0; j<materials.size(); ++j ) { + if( materials[j] == m ) { + index = j; + break; + } + } + if ( index > materials.size() ) { + aiString name(m.name()); + auto* ai_mat = new aiMaterial(); + index = materials.size(); + materials.push_back(m); + ai_mat->AddProperty(&name, AI_MATKEY_NAME); + scene.mMaterials[scene.mNumMaterials] = ai_mat; + ++scene.mNumMaterials; + } + aiMesh* mesh = new aiMesh; + mesh->mName = node_name; + mesh->mMaterialIndex = index; + if ( v.visAttributes().isValid() ) { + float r = 0e0, g = 0e0, b = 0e0, a = 0e0; + v.visAttributes().argb(a, r, g, b); + mesh->mColors[0] = new aiColor4D(r, g, b, a); + } + mesh->mFaces = new aiFace[tes->GetNfacets()]; + mesh->mVertices = new aiVector3D[num_vert]; + mesh->mNormals = new aiVector3D[num_vert]; + mesh->mTangents = nullptr; + mesh->mBitangents = nullptr; + mesh->mNumFaces = 0; + mesh->mNumVertices = 0; + + for( long j=0, n=tes->GetNfacets(); j < n; ++j ) { + aiFace& face = mesh->mFaces[j]; + face.mNumIndices = 0; + face.mIndices = nullptr; + } + vertex vtx, tmp, norm; + for( long j=0, nvx=0, n=tes->GetNfacets(); j < n; ++j ) { + bool degenerated = false; + const auto& facet = tes->GetFacet(j); + tmp = facet.ComputeNormal(degenerated); + if ( !degenerated && facet.GetNvert() > 0 ) { + aiFace& face = mesh->mFaces[mesh->mNumFaces]; + double u = unit_scale; + + face.mIndices = new unsigned int[facet.GetNvert()]; + trafo->LocalToMaster(&tmp.x, &norm.x); + face.mNumIndices = 0; + for( long k=0; k < facet.GetNvert(); ++k ) { + tmp = facet.GetVertex(k); + trafo->LocalToMaster(&tmp.x, &vtx.x); + face.mIndices[face.mNumIndices] = nvx; + mesh->mNormals[nvx] = aiVector3D(norm.x, norm.y, norm.z); + mesh->mVertices[nvx] = aiVector3D(vtx.x*u,vtx.y*u,vtx.z*u); + ++mesh->mNumVertices; + ++face.mNumIndices; + ++nvx; + } + ++mesh->mNumFaces; + } + } + if ( imesh == 122585 ) + break; + else if ( imesh == 122586 ) + mesh->mNumFaces = 0; + else if ( imesh == 122587 ) + mesh->mNumFaces = 0; + + /// Check if we have here a valid mesh + if ( 0 == mesh->mNumFaces || 0 == mesh->mNumVertices ) { + delete [] mesh->mVertices; + mesh->mNumVertices = 0; + delete [] mesh->mNormals; + delete [] mesh->mFaces; + mesh->mNumFaces = 0; + continue; + } + + scene.mMeshes[scene.mNumMeshes] = mesh; + + aiNode *node = new aiNode; + node->mMeshes = new unsigned int[node->mNumMeshes=1]; + node->mMeshes[0] = scene.mNumMeshes; + node->mParent = root; + node->mName.Set("<STL>"); + + root->mChildren[root->mNumChildren] = node; + ++root->mNumChildren; + ++scene.mNumMeshes; + } + printout(ALWAYS,"ASSIMPWriter","+++ Analysed %ld of %ld meshes.", + scene.mNumMeshes, placements.size()); + if ( scene.mNumMeshes > 0 ) { + Assimp::Exporter exporter; + Assimp::ExportProperties *props = new Assimp::ExportProperties; + props->SetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS, + flags&EXPORT_POINT_CLOUDS ? true : false); + exporter.Export(&scene, file_type.c_str(), file_name.c_str(), 0, props); + return 1; + } + return 0; +} diff --git a/DDCAD/src/InputReader.cpp b/DDCAD/src/InputReader.cpp index d581ac31afef637c527843de420bed8370d43a24..2bf36f2821c6637a55ce931f6ed9c0087b6660fe 100644 --- a/DDCAD/src/InputReader.cpp +++ b/DDCAD/src/InputReader.cpp @@ -18,7 +18,8 @@ using namespace dd4hep; using namespace dd4hep::cad; /// Default constructor -InputReader::InputReader() +InputReader::InputReader(Detector& det) + : detector(det) { } diff --git a/DDCAD/src/OutputWriter.cpp b/DDCAD/src/OutputWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4104d022af7ab6c1163dac9ce78d157282341c85 --- /dev/null +++ b/DDCAD/src/OutputWriter.cpp @@ -0,0 +1,29 @@ +//========================================================================== +// AIDA Detector description implementation +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see $DD4hepINSTALL/LICENSE. +// For the list of contributors see $DD4hepINSTALL/doc/CREDITS. +// +// Author : M.Frank +// +//========================================================================== + +/// Framework include files +#include "DDCAD/OutputWriter.h" + +using namespace dd4hep; +using namespace dd4hep::cad; + +/// Default constructor +OutputWriter::OutputWriter(Detector& det) + : detector(det) +{ +} + +/// Default destructor +OutputWriter::~OutputWriter() +{ +} diff --git a/DDCAD/src/plugins/CADPlugins.cpp b/DDCAD/src/plugins/CADPlugins.cpp index 1c7dc8aec4d7c7964bfd1f7d2e08cdb2a1847c51..cbbb1a462e1a8691a499d775509e682c11f5eabc 100644 --- a/DDCAD/src/plugins/CADPlugins.cpp +++ b/DDCAD/src/plugins/CADPlugins.cpp @@ -13,9 +13,11 @@ /// Framework include files #include <DD4hep/DetFactoryHelper.h> +#include <DD4hep/DetectorTools.h> #include <DD4hep/Printout.h> #include <XML/Utilities.h> #include <DDCAD/ASSIMPReader.h> +#include <DDCAD/ASSIMPWriter.h> // C/C++ include files @@ -23,11 +25,48 @@ using namespace std; using namespace dd4hep; using namespace dd4hep::detail; -static Handle<TObject> create_CAD_Shape(Detector&, xml_h e) { +static void* read_CAD_Volume(Detector& dsc, int argc, char** argv) { + string fname; + double scale = 1.0; + bool help = false; + for(int i = 0; i < argc && argv[i]; ++i) { + if ( 0 == ::strncmp( "-input",argv[i],4) ) fname = argv[++i]; + else if ( 0 == ::strncmp("--input",argv[i],5) ) fname = argv[++i]; + else if ( 0 == ::strncmp( "-scale",argv[i],4) ) scale = ::atof(argv[++i]); + else if ( 0 == ::strncmp("--scale",argv[i],5) ) scale = ::atof(argv[++i]); + else if ( 0 == ::strncmp( "-help",argv[i],2) ) help = true; + else if ( 0 == ::strncmp("--help",argv[i],3) ) help = true; + } + + if ( fname.empty() || help ) { + cout << + "Usage: -plugin DD4hep_CAD_export -arg [-arg] \n\n" + " -output <string> Output file name. \n" + " -type <string> Output file type. \n" + " -recursive Export volume/detector element and all daughters.\n" + " -volume <string> Path to the volume to be exported. \n" + " -detector <string> Path to the detector element to be exported. \n" + " -help Print this help output. \n" + " -scale <number> Unit scale before writing output data. \n" + " Arguments given: " << arguments(argc,argv) << endl << flush; + ::exit(EINVAL); + } + + auto volumes = cad::ASSIMPReader(dsc).readVolumes(fname, scale); + if ( volumes.empty() ) { + except("CAD_Volume","+++ CAD file: %s does not contain any " + "understandable tessellated volumes.", fname.c_str()); + } + auto* result = new std::vector<std::unique_ptr<TGeoVolume> >(move(volumes)); + return result; +} +DECLARE_DD4HEP_CONSTRUCTOR(DD4hep_read_CAD_volumes,read_CAD_Volume) + +static Handle<TObject> create_CAD_Shape(Detector& dsc, xml_h e) { xml_elt_t elt(e); string fname = elt.attr<string>(_U(ref)); double unit = elt.hasAttr(_U(unit)) ? elt.attr<double>(_U(unit)) : dd4hep::cm; - auto shapes = cad::ASSIMPReader().read(fname, unit); + auto shapes = cad::ASSIMPReader(dsc).readShapes(fname, unit); if ( shapes.empty() ) { except("CAD_Shape","+++ CAD file: %s does not contain any " "understandable tessellated shapes.", fname.c_str()); @@ -56,29 +95,23 @@ static Handle<TObject> create_CAD_Shape(Detector&, xml_h e) { } DECLARE_XML_SHAPE(CAD_Shape__shape_constructor,create_CAD_Shape) - -static Handle<TObject> create_CAD_MultiShape_Assembly(Detector&, xml_h e) { +static Handle<TObject> create_CAD_Assembly(Detector& dsc, xml_h e) { xml_elt_t elt(e); string fname = elt.attr<string>(_U(ref)); double unit = elt.hasAttr(_U(unit)) ? elt.attr<double>(_U(unit)) : dd4hep::cm; - auto shapes = cad::ASSIMPReader().read(fname, unit); - if ( shapes.empty() ) { + auto volumes = cad::ASSIMPReader(dsc).readVolumes(fname, unit); + if ( volumes.empty() ) { except("CAD_Shape","+++ CAD file: %s does not contain any " - "understandable tessellated shapes.", fname.c_str()); + "understandable tessellated volumes.", fname.c_str()); } Assembly assembly("assembly"); - for(size_t i=0; i < shapes.size(); ++i) { - Solid solid = shapes[i].release(); - if ( solid.isValid() ) { - Volume vol(_toString(int(i),"vol_%d"), solid, Detector::getInstance().material("Air")); - assembly.placeVolume(vol); - } - } + for(size_t i=0; i < volumes.size(); ++i) + assembly.placeVolume(volumes[i].release()); + if ( elt.hasAttr(_U(name)) ) assembly->SetName(elt.attr<string>(_U(name)).c_str()); return assembly; } -DECLARE_XML_VOLUME(CAD_Assembly__volume_constructor,create_CAD_MultiShape_Assembly) - +DECLARE_XML_VOLUME(CAD_Assembly__volume_constructor,create_CAD_Assembly) /// CAD volume importer plugin /** @@ -126,10 +159,10 @@ static Handle<TObject> create_CAD_Volume(Detector& dsc, xml_h e) { xml_elt_t elt(e); string fname = elt.attr<string>(_U(ref)); double unit = elt.attr<double>(_U(unit)); - auto shapes = cad::ASSIMPReader().read(fname, unit); - if ( shapes.empty() ) { + auto volumes = cad::ASSIMPReader(dsc).readVolumes(fname, unit); + if ( volumes.empty() ) { except("CAD_Volume","+++ CAD file: %s does not contain any " - "understandable tessellated shapes.", fname.c_str()); + "understandable tessellated volumes.", fname.c_str()); } Volume envelope; if ( elt.hasChild(_U(envelope)) ) { @@ -165,26 +198,28 @@ static Handle<TObject> create_CAD_Volume(Detector& dsc, xml_h e) { else if ( elt.hasAttr(_U(material)) ) default_material = dsc.material(elt.attr<string>(_U(material))); if ( elt.hasChild(_U(volume)) ) { - map<int, xml_h> shape_map; + map<int, xml_h> volume_map; for (xml_coll_t c(elt,_U(volume)); c; ++c ) - shape_map.emplace(xml_dim_t(c).id(),c); - - for (size_t i=0; i < shapes.size(); ++i) { - Solid sol = shapes[i].release(); - Material mat = default_material; - auto is = shape_map.find(i); - if ( is == shape_map.end() ) { - Volume vol(_toString(int(i),"vol_%d"), sol, mat); + volume_map.emplace(xml_dim_t(c).id(),c); + + for (size_t i=0; i < volumes.size(); ++i) { + Volume vol = volumes[i].release(); + Material mat = default_material; + auto is = volume_map.find(i); + if ( is == volume_map.end() ) { envelope.placeVolume(vol); } else { xml_dim_t x_vol = (*is).second; xml_dim_t x_pos = x_vol.child(_U(position),false); xml_dim_t x_rot = x_vol.child(_U(rotation),false); - string vnam = x_vol.hasAttr(_U(name)) ? x_vol.attr<string>(_U(name)) : _toString(int(i),"vol_%d"); if ( x_vol.hasAttr(_U(material)) ) { - mat = dsc.material(x_vol.attr<string>(_U(material))); + string mat_name = x_vol.attr<string>(_U(material)); + mat = dsc.material(mat_name); + if ( !mat.isValid() ) + except("CAD_MultiVolume","+++ Failed to access material "+mat_name); + vol.setMaterial(mat); } Position pos; RotationZYX rot; @@ -197,7 +232,6 @@ static Handle<TObject> create_CAD_Volume(Detector& dsc, xml_h e) { else if ( x_rot ) rot = RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0)); - Volume vol(vnam, sol, mat); PlacedVolume pv = envelope.placeVolume(vol,env_trafo*Transform3D(rot, pos)); vol.setAttributes(dsc, x_vol.regionStr(), x_vol.limitsStr(), x_vol.visStr()); for (xml_coll_t cc(x_vol,_U(physvolid)); cc; ++cc ) { @@ -208,10 +242,11 @@ static Handle<TObject> create_CAD_Volume(Detector& dsc, xml_h e) { } } else { - for(size_t i=0; i < shapes.size(); ++i) { - Solid solid = shapes[i].release(); - if ( solid.isValid() ) { - Volume vol(_toString(int(i),"vol_%d"), solid, default_material); + for(size_t i=0; i < volumes.size(); ++i) { + Volume vol = volumes[i].release(); + if ( vol.isValid() ) { + if ( (vol.material() == dsc.air()) && default_material.isValid() ) + vol.setMaterial(default_material); envelope.placeVolume(vol); } } @@ -220,3 +255,77 @@ static Handle<TObject> create_CAD_Volume(Detector& dsc, xml_h e) { return envelope; } DECLARE_XML_VOLUME(CAD_MultiVolume__volume_constructor,create_CAD_Volume) + +/// CAD volume importer plugin +/** + * + */ +static long CAD_export(Detector& description, int argc, char** argv) { + bool recursive = false, help = false; + string volume, detector, fname, ftype; + double scale = 1.0; + + for(int i = 0; i < argc && argv[i]; ++i) { + if ( 0 == ::strncmp( "-output",argv[i],4) ) fname = argv[++i]; + else if ( 0 == ::strncmp("--output",argv[i],5) ) fname = argv[++i]; + else if ( 0 == ::strncmp( "-type",argv[i],4) ) ftype = argv[++i]; + else if ( 0 == ::strncmp("--type",argv[i],5) ) ftype = argv[++i]; + else if ( 0 == ::strncmp( "-detector",argv[i],4) ) detector = argv[++i]; + else if ( 0 == ::strncmp("--detector",argv[i],5) ) detector = argv[++i]; + else if ( 0 == ::strncmp( "-volume",argv[i],4) ) volume = argv[++i]; + else if ( 0 == ::strncmp("--volume",argv[i],5) ) volume = argv[++i]; + else if ( 0 == ::strncmp( "-recursive",argv[i],4) ) recursive = true; + else if ( 0 == ::strncmp("--recursive",argv[i],5) ) recursive = true; + else if ( 0 == ::strncmp( "-scale",argv[i],4) ) scale = ::atof(argv[++i]); + else if ( 0 == ::strncmp("--scale",argv[i],5) ) scale = ::atof(argv[++i]); + else if ( 0 == ::strncmp( "-help",argv[i],2) ) help = true; + else if ( 0 == ::strncmp("--help",argv[i],3) ) help = true; + } + + if ( fname.empty() || ftype.empty() ) help = true; + if ( volume.empty() && detector.empty() ) help = true; + if ( help ) { + cout << + "Usage: -plugin DD4hep_CAD_export -arg [-arg] \n\n" + " -output <string> Output file name. \n" + " -type <string> Output file type. \n" + " -recursive Export volume/detector element and all daughters.\n" + " -volume <string> Path to the volume to be exported. \n" + " -detector <string> Path to the detector element to be exported. \n" + " -help Print this help output. \n" + " -scale <number> Unit scale before writing output data. \n" + " Arguments given: " << arguments(argc,argv) << endl << flush; + ::exit(EINVAL); + } + + PlacedVolume pv; + if ( !detector.empty() ) { + DetElement elt; + if ( detector == "/world" ) + elt = description.world(); + else + elt = detail::tools::findElement(description,detector); + if ( !elt.isValid() ) { + except("DD4hep_CAD_export","+++ Invalid DetElement path: %s",detector.c_str()); + } + if ( !elt.placement().isValid() ) { + except("DD4hep_CAD_export","+++ Invalid DetElement placement: %s",detector.c_str()); + } + pv = elt.placement(); + } + else if ( !volume.empty() ) { + pv = detail::tools::findNode(description.world().placement(), volume); + if ( !pv.isValid() ) { + except("DD4hep_CAD_export","+++ Invalid placement path: %s",volume.c_str()); + } + } + cad::ASSIMPWriter wr(description); + std::vector<PlacedVolume> places {pv}; + auto num_mesh = wr.write(fname, ftype, places, recursive, scale); + if ( num_mesh < 0 ) { + printout(ERROR, "DD4hep_CAD_export","+++ Failed to export shapes to CAD file: %s [%s]", + fname.c_str(), ftype.c_str()); + } + return 1; +} +DECLARE_APPLY(DD4hep_CAD_export,CAD_export) diff --git a/DDCore/include/DD4hep/Shapes.h b/DDCore/include/DD4hep/Shapes.h index ae9102ee9f3bb03cd1c2f12d39f48c2151874ac4..952ea6b1458a4b44143eb17b4cd5cfe2da3496f2 100644 --- a/DDCore/include/DD4hep/Shapes.h +++ b/DDCore/include/DD4hep/Shapes.h @@ -1776,8 +1776,10 @@ namespace dd4hep { void make(const std::string& nam, const std::vector<Object::Vertex_t>& vertices); public: - typedef Object::Vertex_t Vertex_t; - + typedef Object::Vertex_t Vertex; + typedef TGeoFacet Facet; + + public: /// Default constructor TessellatedSolid() = default; /// Move Constructor @@ -1794,7 +1796,7 @@ namespace dd4hep { { this->make("", num_facets); } /// Constructor to create a new identified object with attribute initialization - TessellatedSolid(const std::vector<Vertex_t>& vertices) + TessellatedSolid(const std::vector<Vertex>& vertices) { this->make("", vertices); } /// Constructor to create a new anonymous object with attribute initialization @@ -1802,7 +1804,7 @@ namespace dd4hep { { this->make(nam, num_facets); } /// Constructor to create a new identified object with attribute initialization - TessellatedSolid(const std::string& nam, const std::vector<Vertex_t>& vertices) + TessellatedSolid(const std::string& nam, const std::vector<Vertex>& vertices) { this->make(nam, vertices); } /// Move Assignment operator @@ -1810,13 +1812,22 @@ namespace dd4hep { /// Copy Assignment operator TessellatedSolid& operator=(const TessellatedSolid& copy) = default; /// Add new facet to the shape - bool addFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2) const; + bool addFacet(const Vertex& pt0, const Vertex& pt1, const Vertex& pt2) const; /// Add new facet to the shape - bool addFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2, const Vertex_t& pt3) const; + bool addFacet(const Vertex& pt0, const Vertex& pt1, const Vertex& pt2, const Vertex& pt3) const; /// Add new facet to the shape. Call only if the tessellated shape was constructed with vertices bool addFacet(const int pt0, const int pt1, const int pt2) const; /// Add new facet to the shape. Call only if the tessellated shape was constructed with vertices bool addFacet(const int pt0, const int pt1, const int pt2, const int pt3) const; + + /// Access the number of facets in the shape + int num_facet() const; + /// Access a facet from the built shape + const Facet& facet(int index) const; + /// Access the number of vertices in the shape + int num_vertex() const; + /// Access a single vertex from the shape + const Vertex& vertex(int index) const; }; #endif diff --git a/DDCore/src/ShapeUtilities.cpp b/DDCore/src/ShapeUtilities.cpp index f455af8bec3b5bba6230190510807aed61a33d0a..9050c489f4f5b8655949e87451379f25c145662d 100644 --- a/DDCore/src/ShapeUtilities.cpp +++ b/DDCore/src/ShapeUtilities.cpp @@ -752,7 +752,7 @@ namespace dd4hep { template <> void set_dimensions(TGeoTessellated* sh, const std::vector<double>& params) { int num_vtx = params[0]; int num_facet = params[1]; - std::vector<TessellatedSolid::Vertex_t> vertices; + std::vector<TessellatedSolid::Vertex> vertices; size_t i_par = 1; printout(DEBUG,"TessellatedSolid","+++ Loading %d vertices, %d facets",num_vtx, num_facet); for (int i=0; i<num_vtx; ++i) { diff --git a/DDCore/src/Shapes.cpp b/DDCore/src/Shapes.cpp index 812ced7be7214410cd11ea04268147feb6fe0be6..9786e02e0589084099a1cce37b83797167fb0ec2 100644 --- a/DDCore/src/Shapes.cpp +++ b/DDCore/src/Shapes.cpp @@ -794,17 +794,17 @@ void TessellatedSolid::make(const std::string& nam, int num_facets) { } /// Internal helper method to support object construction -void TessellatedSolid::make(const std::string& nam, const std::vector<Object::Vertex_t>& vertices) { +void TessellatedSolid::make(const std::string& nam, const std::vector<Vertex>& vertices) { _assign(new TGeoTessellated(nam.c_str(), vertices), nam, TESSELLATEDSOLID_TAG, false); } /// Add new facet to the shape -bool TessellatedSolid::addFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2) const { +bool TessellatedSolid::addFacet(const Vertex& pt0, const Vertex& pt1, const Vertex& pt2) const { return access()->AddFacet(pt0, pt1, pt2); } /// Add new facet to the shape -bool TessellatedSolid::addFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2, const Vertex_t& pt3) const { +bool TessellatedSolid::addFacet(const Vertex& pt0, const Vertex& pt1, const Vertex& pt2, const Vertex& pt3) const { return access()->AddFacet(pt0, pt1, pt2, pt3); } @@ -817,6 +817,26 @@ bool TessellatedSolid::addFacet(const int pt0, const int pt1, const int pt2) co bool TessellatedSolid::addFacet(const int pt0, const int pt1, const int pt2, const int pt3) const { return access()->AddFacet(pt0, pt1, pt2, pt3); } + +/// Access the number of facets in the shape +int TessellatedSolid::num_facet() const { + return access()->GetNvertices(); +} + +/// Access a facet from the built shape +const TessellatedSolid::Facet& TessellatedSolid::facet(int index) const { + return ptr()->GetFacet(index); +} + +/// Access the number of vertices in the shape +int TessellatedSolid::num_vertex() const { + return access()->GetNvertices(); +} + +/// Access a single vertex from the shape +const TessellatedSolid::Vertex& TessellatedSolid::vertex(int index) const { + return ptr()->GetVertex(index); +} #endif /// Access right solid of the boolean diff --git a/DDCore/src/plugins/ShapePlugins.cpp b/DDCore/src/plugins/ShapePlugins.cpp index d456c166360094bd490db9c8a26ce798b1bc3a83..e2444890a1da76341b1da8ff108f2f63ff930a4a 100644 --- a/DDCore/src/plugins/ShapePlugins.cpp +++ b/DDCore/src/plugins/ShapePlugins.cpp @@ -394,7 +394,7 @@ DECLARE_XML_SHAPE(EightPointSolid__shape_constructor,create_EightPointSolid) /// Plugin factory to created tessellated shapes static Handle<TObject> create_TessellatedSolid(Detector&, xml_h element) { xml_dim_t e(element); - std::vector<TessellatedSolid::Vertex_t> vertices; + std::vector<TessellatedSolid::Vertex> vertices; for ( xml_coll_t vtx(element, _U(vertex)); vtx; ++vtx ) { xml_dim_t v(vtx); vertices.emplace_back(v.x(), v.y(), v.z()); diff --git a/DDCore/src/plugins/StandardPlugins.cpp b/DDCore/src/plugins/StandardPlugins.cpp index 4eb52cb0fa729a97756e6bd523b94cb9acdc3d09..34211d8bf7a5b4dc023397c3a275ef24a89a7a8e 100644 --- a/DDCore/src/plugins/StandardPlugins.cpp +++ b/DDCore/src/plugins/StandardPlugins.cpp @@ -1437,20 +1437,20 @@ template <int flag> long dump_detelement_tree(Detector& description, int argc, c else { cout << " " << (flag==0 ? "DD4hep_DetectorDump" : "DD4hep_DetectorVolumeDump") << " -arg [-arg] \n" - " --sensitive Process only sensitive volumes. \n" + " --sensitive Process only sensitive volumes. \n" " -sensitive dto. \n" - " --no-sensitive Invert sensitive only flag. \n" + " --no-sensitive Invert sensitive only flag. \n" " -no-sensitive dto. \n" - " --shapes Print shape information. \n" + " --shapes Print shape information. \n" " -shapes dto. \n" - " --positions Print position information. \n" + " --positions Print position information. \n" " -positions dto. \n" - " --materials Print material information. \n" + " --materials Print material information. \n" " -materials dto. \n" - " --detector <path> Process elements only if <path> is part of the DetElement path.\n" + " --detector <path> Process elements only if <path> is part of the DetElement path.\n" " -detector <path> dto. \n" " -level <number> Maximal depth to be explored by the scan \n" - " --level <number> dto. \n" + " --level <number> dto. \n" "\tArguments given: " << arguments(argc,argv) << endl << flush; ::exit(EINVAL); } diff --git a/DDG4/include/DDG4/Geant4PhysicsList.h b/DDG4/include/DDG4/Geant4PhysicsList.h index d15c19fb654f9a508ba0315eca6d5628c7ef29aa..8fe5f2ef014776abc99e07de4bcd55ed81fafb51 100644 --- a/DDG4/include/DDG4/Geant4PhysicsList.h +++ b/DDG4/include/DDG4/Geant4PhysicsList.h @@ -65,6 +65,11 @@ namespace dd4hep { typedef std::map<std::string, ParticleProcesses> PhysicsProcesses; /// Structure describing a G4 particle constructor + /** + * \author M.Frank + * \version 1.0 + * \ingroup DD4HEP_SIMULATION + */ class ParticleConstructor : public std::string { public: /// Default constructor @@ -141,6 +146,9 @@ namespace dd4hep { /// Access discrete processes for one particle type (CONST) const ParticleProcesses& discreteProcesses(const std::string& part_name) const; + /// Access physics constructor by name + PhysicsConstructor physics(const std::string& name) const; + /// Access all physics particles ParticleConstructors& particles() { return m_particles; diff --git a/DDG4/plugins/Geant4SDActions.cpp b/DDG4/plugins/Geant4SDActions.cpp index a51a99b4c5224ece19c7961ef6a2fe8e81593015..f624521f6800d505fdca3b2db657e3323ffa5c37 100644 --- a/DDG4/plugins/Geant4SDActions.cpp +++ b/DDG4/plugins/Geant4SDActions.cpp @@ -47,12 +47,16 @@ namespace dd4hep { } /// Method for generating hit(s) using the information of G4Step object. - template <> bool Geant4SensitiveAction<Geant4VoidSensitive>::process(G4Step* /*step*/,G4TouchableHistory* /*hist*/ ) { + template <> bool + Geant4SensitiveAction<Geant4VoidSensitive>::process(G4Step* /* step */, + G4TouchableHistory* /* hist */) { return true; } /// Method for generating hit(s) using the information of G4Step object. - template <> bool Geant4SensitiveAction<Geant4VoidSensitive>::processGFlash(G4GFlashSpot* /*spot*/,G4TouchableHistory* /*hist*/ ) { + template <> bool + Geant4SensitiveAction<Geant4VoidSensitive>::processGFlash(G4GFlashSpot* /* spot */, + G4TouchableHistory* /* hist */) { return true; } typedef Geant4SensitiveAction<Geant4VoidSensitive> Geant4VoidSensitiveAction; @@ -75,7 +79,8 @@ namespace dd4hep { } /// Method for generating hit(s) using the information of G4Step object. - template <> bool Geant4SensitiveAction<Geant4Tracker>::process(G4Step* step,G4TouchableHistory* /*hist*/ ) { + template <> bool + Geant4SensitiveAction<Geant4Tracker>::process(G4Step* step,G4TouchableHistory* /* hist */) { typedef Geant4Tracker::Hit Hit; Geant4StepHandler h(step); Position prePos = h.prePos(); @@ -111,8 +116,9 @@ namespace dd4hep { } /// Method for generating hit(s) using the information of G4Step object. - template <> bool Geant4SensitiveAction<Geant4Tracker>::processGFlash(G4GFlashSpot* spot, - G4TouchableHistory* /*hist*/ ) + template <> bool + Geant4SensitiveAction<Geant4Tracker>::processGFlash(G4GFlashSpot* spot, + G4TouchableHistory* /* hist */) { typedef Geant4Tracker::Hit Hit; Geant4GFlashSpotHandler h(spot); @@ -155,7 +161,8 @@ namespace dd4hep { } /// Method for generating hit(s) using the information of G4Step object. - template <> bool Geant4SensitiveAction<Geant4Calorimeter>::process(G4Step* step,G4TouchableHistory*) { + template <> bool + Geant4SensitiveAction<Geant4Calorimeter>::process(G4Step* step,G4TouchableHistory*) { typedef Geant4Calorimeter::Hit Hit; Geant4StepHandler h(step); HitContribution contrib = Hit::extractContribution(step); diff --git a/DDG4/src/Geant4PhysicsList.cpp b/DDG4/src/Geant4PhysicsList.cpp index e87478af1b8dae818aa1fd34ea2e439ba2ac0ae4..f63f863b25a22687f2772e375108d4719b848054 100644 --- a/DDG4/src/Geant4PhysicsList.cpp +++ b/DDG4/src/Geant4PhysicsList.cpp @@ -199,6 +199,19 @@ const Geant4PhysicsList::ParticleProcesses& Geant4PhysicsList::discreteProcesses throw runtime_error("Failed to access the physics process"); // never called anyway } +/// Access physics constructor by name (CONST) +Geant4PhysicsList::PhysicsConstructor Geant4PhysicsList::physics(const std::string& nam) const { + for ( const auto& ctor : m_physics ) { + if ( ctor == nam ) { + if ( nullptr == ctor.pointer ) + except("Failed to instaniate the physics for constructor '%s'", nam.c_str()); + return ctor; + } + } + except("Failed to access the physics for constructor '%s' [Unknown physics]", nam.c_str()); + throw runtime_error("Failed to access the physics process"); // never called anyway +} + /// Add PhysicsConstructor by name void Geant4PhysicsList::adoptPhysicsConstructor(Geant4Action* action) { if ( 0 != action ) { @@ -219,11 +232,10 @@ void Geant4PhysicsList::constructPhysics(G4VModularPhysicsList* physics_pointer) debug("constructPhysics %p", physics_pointer); for ( auto& ctor : m_physics ) { if ( 0 == ctor.pointer ) { - if ( G4VPhysicsConstructor* p = PluginService::Create<G4VPhysicsConstructor*>(ctor) ) { + if ( G4VPhysicsConstructor* p = PluginService::Create<G4VPhysicsConstructor*>(ctor) ) ctor.pointer = p; - continue; - } - except("Failed to create the physics for G4VPhysicsConstructor '%s'", ctor.c_str()); + else + except("Failed to create the physics for G4VPhysicsConstructor '%s'", ctor.c_str()); } physics_pointer->RegisterPhysics(ctor.pointer); info("Registered Geant4 physics constructor %s to physics list", ctor.c_str()); @@ -239,7 +251,7 @@ void Geant4PhysicsList::constructParticles(G4VUserPhysicsList* physics_pointer) if ( !def ) { /// Check if we have here a particle group constructor long* result = (long*) PluginService::Create<long>(ctor); - if (!result || *result != 1L) { + if ( !result || *result != 1L ) { except("Failed to create particle type '%s' result=%d", ctor.c_str(), result); } info("Constructed Geant4 particle %s [using signature long (*)()]",ctor.c_str()); @@ -249,7 +261,7 @@ void Geant4PhysicsList::constructParticles(G4VUserPhysicsList* physics_pointer) for ( const auto& ctor : m_particlegroups ) { /// Check if we have here a particle group constructor long* result = (long*) PluginService::Create<long>(ctor); - if (!result || *result != 1L) { + if ( !result || *result != 1L ) { except("Failed to create particle type '%s' result=%d", ctor.c_str(), result); } info("Constructed Geant4 particle group %s [using signature long (*)()]",ctor.c_str()); diff --git a/examples/DDCAD/compact/Check_Shape_MS3D_jeep.xml b/examples/DDCAD/compact/Check_Shape_MS3D_jeep.xml index e7a5c4830d62000bfd2fbbec9e90c99caebb7bf2..257ba1f67b48a0b54ededaee3aa27c55bad3e0dc 100644 --- a/examples/DDCAD/compact/Check_Shape_MS3D_jeep.xml +++ b/examples/DDCAD/compact/Check_Shape_MS3D_jeep.xml @@ -18,7 +18,7 @@ <detectors> <detector id="1" name="Shape_OBJ" type="DD4hep_TestShape_Creator"> <check vis="Shape1_vis"> - <shape type="CAD_Assembly" ref="${DD4hepExamplesINSTALL}/examples/DDCAD/models/MS3D/jeep1.ms3d"/> + <shape type="CAD_MultiVolume" ref="${DD4hepExamplesINSTALL}/examples/DDCAD/models/MS3D/jeep1.ms3d"/> </check> <test1 type="DD4hep_Mesh_Verifier" ref="${DD4hepExamplesINSTALL}/examples/DDCAD/ref/Ref_OBJ_spider.txt" create="CheckShape_create"/> </detector>