File indexing completed on 2025-01-18 09:13:25
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <DD4hep/DetFactoryHelper.h>
0016 #include <DD4hep/DetectorTools.h>
0017 #include <DD4hep/Printout.h>
0018 #include <XML/Utilities.h>
0019 #include <DDCAD/ASSIMPReader.h>
0020 #include <DDCAD/ASSIMPWriter.h>
0021
0022
0023 #include <filesystem>
0024
0025 using dd4hep::except;
0026 using dd4hep::printout;
0027
0028
0029 static std::string resolve_path(xml_h e, const std::string& file) {
0030 std::error_code errc;
0031 std::string fname;
0032
0033 if ( file.length() > 7 && file.substr(0,7) == "file://" )
0034 fname = file.substr(7);
0035 else
0036 fname = file;
0037 if ( !std::filesystem::exists(fname, errc) ) {
0038 std::string fn = dd4hep::xml::DocumentHandler::system_path(e, fname);
0039 if ( fn.length() > 7 && fn.substr(0,7) == "file://" )
0040 fn = fn.substr(7);
0041 if ( !std::filesystem::exists(fn, errc) ) {
0042 auto fp = std::filesystem::path(dd4hep::xml::DocumentHandler::system_path(e)).parent_path();
0043 except("CAD_Shape","+++ CAD file: %s (= %s + %s) is not accessible [%d: %s]",
0044 fn.c_str(), fp.c_str(), fname.c_str(),
0045 errc.value(), errc.message().c_str());
0046 }
0047 return fn;
0048 }
0049 return fname;
0050 }
0051
0052 static void* read_CAD_Volume(dd4hep::Detector& dsc, int argc, char** argv) {
0053 std::string fname;
0054 double scale = 1.0;
0055 bool help = false;
0056 for(int i = 0; i < argc && argv[i]; ++i) {
0057 if ( 0 == ::strncmp( "-input",argv[i],4) ) fname = argv[++i];
0058 else if ( 0 == ::strncmp("--input",argv[i],5) ) fname = argv[++i];
0059 else if ( 0 == ::strncmp( "-scale",argv[i],4) ) scale = ::atof(argv[++i]);
0060 else if ( 0 == ::strncmp("--scale",argv[i],5) ) scale = ::atof(argv[++i]);
0061 else if ( 0 == ::strncmp( "-help",argv[i],2) ) help = true;
0062 else if ( 0 == ::strncmp("--help",argv[i],3) ) help = true;
0063 }
0064
0065 if ( fname.empty() || help ) {
0066 std::cout <<
0067 "Usage: -plugin DD4hep_CAD_export -arg [-arg] \n\n"
0068 " -input <string> Input file name. \n"
0069 " -scale <float> Scale factor when importing shapes. \n"
0070 " -help Print this help output. \n"
0071 " Arguments given: " << dd4hep::arguments(argc,argv) << std::endl << std::flush;
0072 ::exit(EINVAL);
0073 }
0074
0075 auto volumes = dd4hep::cad::ASSIMPReader(dsc).readVolumes(fname, scale);
0076 if ( volumes.empty() ) {
0077 except("CAD_Volume","+++ CAD file: %s does not contain any "
0078 "understandable tessellated volumes.", fname.c_str());
0079 }
0080 auto* result = new std::vector<std::unique_ptr<TGeoVolume> >(move(volumes));
0081 return result;
0082 }
0083 DECLARE_DD4HEP_CONSTRUCTOR(DD4hep_read_CAD_volumes,read_CAD_Volume)
0084
0085 static dd4hep::Handle<TObject> create_CAD_Shape(dd4hep::Detector& dsc, xml_h e) {
0086 xml_elt_t elt(e);
0087 dd4hep::cad::ASSIMPReader rdr(dsc);
0088 std::string fname = resolve_path(e, elt.attr<std::string>(_U(ref)));
0089 long flags = elt.hasAttr(_U(flags)) ? elt.attr<long>(_U(flags)) : 0;
0090 double unit = elt.hasAttr(_U(unit)) ? elt.attr<double>(_U(unit)) : dd4hep::cm;
0091
0092 if ( flags ) rdr.flags = flags;
0093 auto shapes = rdr.readShapes(fname, unit);
0094 if ( shapes.empty() ) {
0095 except("CAD_Shape","+++ CAD file: %s does not contain any "
0096 "understandable tessellated shapes.", fname.c_str());
0097 }
0098 dd4hep::Solid solid;
0099 std::size_t count = shapes.size();
0100 if ( count == 1 ) {
0101 solid = shapes[0].release();
0102 }
0103 else {
0104 if ( elt.hasAttr(_U(item)) ) {
0105 std::size_t which = elt.attr<std::size_t>(_U(item));
0106 solid = shapes[which].release();
0107 }
0108 else if ( elt.hasAttr(_U(mesh)) ) {
0109 std::size_t which = elt.attr<std::size_t>(_U(mesh));
0110 solid = shapes[which].release();
0111 }
0112 else {
0113 except("CAD_Shape","+++ CAD file: %s does contains %ld tessellated shapes. "
0114 "You need to add a selector.", fname.c_str(), shapes.size());
0115 }
0116 }
0117 if ( elt.hasAttr(_U(name)) ) solid->SetName(elt.attr<std::string>(_U(name)).c_str());
0118 return solid;
0119 }
0120 DECLARE_XML_SHAPE(CAD_Shape__shape_constructor,create_CAD_Shape)
0121
0122 static dd4hep::Handle<TObject> create_CAD_Assembly(dd4hep::Detector& dsc, xml_h e) {
0123 xml_elt_t elt(e);
0124 std::string fname = resolve_path(e, elt.attr<std::string>(_U(ref)));
0125 double unit = elt.hasAttr(_U(unit)) ? elt.attr<double>(_U(unit)) : dd4hep::cm;
0126 auto volumes = dd4hep::cad::ASSIMPReader(dsc).readVolumes(fname, unit);
0127 if ( volumes.empty() ) {
0128 except("CAD_Shape","+++ CAD file: %s does not contain any "
0129 "understandable tessellated volumes.", fname.c_str());
0130 }
0131 dd4hep::Assembly assembly("assembly");
0132 for(std::size_t i=0; i < volumes.size(); ++i) {
0133 dd4hep::Volume vol(volumes[i].release());
0134 assembly.placeVolume(vol);
0135 }
0136
0137 if ( elt.hasAttr(_U(name)) ) assembly->SetName(elt.attr<std::string>(_U(name)).c_str());
0138 return assembly;
0139 }
0140 DECLARE_XML_VOLUME(CAD_Assembly__volume_constructor,create_CAD_Assembly)
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186 static dd4hep::Handle<TObject> create_CAD_Volume(dd4hep::Detector& dsc, xml_h e) {
0187 xml_elt_t elt(e);
0188 double unit = elt.attr<double>(_U(unit));
0189 std::string fname = resolve_path(e, elt.attr<std::string>(_U(ref)));
0190 long flags = elt.hasAttr(_U(flags)) ? elt.attr<long>(_U(flags)) : 0;
0191 dd4hep::cad::ASSIMPReader rdr(dsc);
0192
0193 if ( flags ) rdr.flags = flags;
0194 auto volumes = rdr.readVolumes(fname, unit);
0195 if ( volumes.empty() ) {
0196 except("CAD_Volume","+++ CAD file: %s does not contain any "
0197 "understandable tessellated volumes.", fname.c_str());
0198 }
0199 dd4hep::Volume envelope;
0200 if ( elt.hasChild(_U(envelope)) ) {
0201 std::string typ = "DD4hep_StdVolume";
0202 xml_h x_env = elt.child(_U(envelope));
0203 TObject* pvol = dd4hep::PluginService::Create<TObject*>(typ, &dsc, &x_env);
0204 envelope = dynamic_cast<TGeoVolume*>(pvol);
0205 if ( !envelope.isValid() ) {
0206 except("CAD_Volume", "+++ Unable to determine envelope to CAD shape: %s",fname.c_str());
0207 }
0208 }
0209 else {
0210 envelope = dd4hep::Assembly("envelope");
0211 }
0212 xml_dim_t x_envpos = elt.child(_U(position),false);
0213 xml_dim_t x_envrot = elt.child(_U(rotation),false);
0214 dd4hep::Position env_pos;
0215 dd4hep::RotationZYX env_rot;
0216 if ( x_envpos && x_envrot ) {
0217 env_rot = dd4hep::RotationZYX(x_envrot.z(0), x_envrot.y(0), x_envrot.x(0));
0218 env_pos = dd4hep::Position(x_envpos.x(0), x_envpos.y(0), x_envpos.z(0));
0219 }
0220 else if ( x_envpos )
0221 env_pos = dd4hep::Position(x_envpos.x(0), x_envpos.y(0), x_envpos.z(0));
0222 else if ( x_envrot )
0223 env_rot = dd4hep::RotationZYX(x_envrot.z(0), x_envrot.y(0), x_envrot.x(0));
0224
0225 dd4hep::Transform3D env_trafo(env_rot, env_pos);
0226 dd4hep::Material default_material;
0227 xml_dim_t x_mat = elt.child(_U(material),false);
0228 if ( x_mat.ptr() ) default_material = dsc.material(x_mat.nameStr());
0229 else if ( elt.hasAttr(_U(material)) ) default_material = dsc.material(elt.attr<std::string>(_U(material)));
0230
0231 if ( elt.hasChild(_U(volume)) ) {
0232 std::map<int, xml_h> volume_map;
0233 for (xml_coll_t c(elt,_U(volume)); c; ++c )
0234 volume_map.emplace(xml_dim_t(c).id(),c);
0235
0236 for (std::size_t i=0; i < volumes.size(); ++i) {
0237 dd4hep::Volume vol = volumes[i].release();
0238 dd4hep::Material mat = default_material;
0239 auto is = volume_map.find(i);
0240 if ( is == volume_map.end() ) {
0241 envelope.placeVolume(vol);
0242 }
0243 else {
0244 xml_dim_t x_vol = (*is).second;
0245 xml_dim_t x_pos = x_vol.child(_U(position),false);
0246 xml_dim_t x_rot = x_vol.child(_U(rotation),false);
0247
0248 if ( x_vol.hasAttr(_U(material)) ) {
0249 std::string mat_name = x_vol.attr<std::string>(_U(material));
0250 mat = dsc.material(mat_name);
0251 if ( !mat.isValid() )
0252 except("CAD_MultiVolume","+++ Failed to access material "+mat_name);
0253 vol.setMaterial(mat);
0254 }
0255 dd4hep::Position pos;
0256 dd4hep::RotationZYX rot;
0257 if ( x_pos && x_rot ) {
0258 rot = dd4hep::RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0));
0259 pos = dd4hep::Position(x_pos.x(0), x_pos.y(0), x_pos.z(0));
0260 }
0261 else if ( x_pos )
0262 pos = dd4hep::Position(x_pos.x(0), x_pos.y(0), x_pos.z(0));
0263 else if ( x_rot )
0264 rot = dd4hep::RotationZYX(x_rot.z(0), x_rot.y(0), x_rot.x(0));
0265
0266 dd4hep::PlacedVolume pv = envelope.placeVolume(vol,env_trafo*dd4hep::Transform3D(rot, pos));
0267 vol.setAttributes(dsc, x_vol.regionStr(), x_vol.limitsStr(), x_vol.visStr());
0268 for (xml_coll_t cc(x_vol,_U(physvolid)); cc; ++cc ) {
0269 xml_dim_t vid = cc;
0270 pv.addPhysVolID(vid.nameStr(), vid.attr<int>(_U(value)));
0271 }
0272 }
0273 }
0274 }
0275 else {
0276 for(std::size_t i=0; i < volumes.size(); ++i) {
0277 dd4hep::Volume vol = volumes[i].release();
0278 if ( vol.isValid() ) {
0279 if ( (vol.material() == dsc.air()) && default_material.isValid() )
0280 vol.setMaterial(default_material);
0281 envelope.placeVolume(vol,env_trafo);
0282 }
0283 }
0284 }
0285 if ( elt.hasAttr(_U(name)) ) envelope->SetName(elt.attr<std::string>(_U(name)).c_str());
0286 return envelope;
0287 }
0288 DECLARE_XML_VOLUME(CAD_MultiVolume__volume_constructor,create_CAD_Volume)
0289
0290
0291
0292
0293
0294 static long CAD_export(dd4hep::Detector& description, int argc, char** argv) {
0295 bool recursive = false, help = false;
0296 std::string volume, detector, fname, ftype;
0297 double scale = 1.0;
0298 int flags = 0;
0299
0300 for(int i = 0; i < argc && argv[i]; ++i) {
0301 if ( 0 == ::strncmp( "-output",argv[i],4) ) fname = argv[++i];
0302 else if ( 0 == ::strncmp("--output",argv[i],5) ) fname = argv[++i];
0303 else if ( 0 == ::strncmp( "-type",argv[i],4) ) ftype = argv[++i];
0304 else if ( 0 == ::strncmp("--type",argv[i],5) ) ftype = argv[++i];
0305 else if ( 0 == ::strncmp( "-detector",argv[i],4) ) detector = argv[++i];
0306 else if ( 0 == ::strncmp("--detector",argv[i],5) ) detector = argv[++i];
0307 else if ( 0 == ::strncmp( "-volume",argv[i],4) ) volume = argv[++i];
0308 else if ( 0 == ::strncmp("--volume",argv[i],5) ) volume = argv[++i];
0309 else if ( 0 == ::strncmp( "-recursive",argv[i],4) ) recursive = true;
0310 else if ( 0 == ::strncmp("--recursive",argv[i],5) ) recursive = true;
0311 else if ( 0 == ::strncmp( "-scale",argv[i],4) ) scale = ::atof(argv[++i]);
0312 else if ( 0 == ::strncmp("--scale",argv[i],5) ) scale = ::atof(argv[++i]);
0313 else if ( 0 == ::strncmp( "-flags",argv[i],4) ) flags = ::atol(argv[++i]);
0314 else if ( 0 == ::strncmp("--flags",argv[i],5) ) flags = ::atol(argv[++i]);
0315 else if ( 0 == ::strncmp( "-help",argv[i],2) ) help = true;
0316 else if ( 0 == ::strncmp("--help",argv[i],3) ) help = true;
0317 }
0318
0319 if ( fname.empty() || ftype.empty() ) help = true;
0320 if ( volume.empty() && detector.empty() ) help = true;
0321 if ( help ) {
0322 std::cout <<
0323 "Usage: -plugin DD4hep_CAD_export -arg [-arg] \n\n"
0324 " -output <string> Output file name. \n"
0325 " -type <string> Output file type. \n"
0326 " -recursive Export volume/detector element and all daughters.\n"
0327 " -volume <string> Path to the volume to be exported. \n"
0328 " -detector <string> Path to the detector element to be exported. \n"
0329 " -help Print this help output. \n"
0330 " -scale <number> Unit scale before writing output data. \n"
0331 " -flags <number> Flagsging helper to pass args -- Experts only. \n"
0332 " Arguments given: " << dd4hep::arguments(argc,argv) << std::endl << std::flush;
0333 ::exit(EINVAL);
0334 }
0335
0336 dd4hep::PlacedVolume pv;
0337 if ( !detector.empty() ) {
0338 dd4hep::DetElement elt;
0339 if ( detector == "/world" )
0340 elt = description.world();
0341 else
0342 elt = dd4hep::detail::tools::findElement(description,detector);
0343 if ( !elt.isValid() ) {
0344 except("DD4hep_CAD_export","+++ Invalid DetElement path: %s",detector.c_str());
0345 }
0346 if ( !elt.placement().isValid() ) {
0347 except("DD4hep_CAD_export","+++ Invalid DetElement placement: %s",detector.c_str());
0348 }
0349 pv = elt.placement();
0350 }
0351 else if ( !volume.empty() ) {
0352 pv = dd4hep::detail::tools::findNode(description.world().placement(), volume);
0353 if ( !pv.isValid() ) {
0354 except("DD4hep_CAD_export","+++ Invalid placement path: %s",volume.c_str());
0355 }
0356 }
0357 dd4hep::cad::ASSIMPWriter wr(description);
0358 if ( flags ) wr.flags = flags;
0359 std::vector<dd4hep::PlacedVolume> places {pv};
0360 auto num_mesh = wr.write(fname, ftype, places, recursive, scale);
0361 if ( num_mesh < 0 ) {
0362 printout(dd4hep::ERROR, "DD4hep_CAD_export",
0363 "+++ Failed to export shapes to CAD file: %s [%s]",
0364 fname.c_str(), ftype.c_str());
0365 }
0366 return 1;
0367 }
0368 DECLARE_APPLY(DD4hep_CAD_export,CAD_export)