From 79bf759419587470cd18c46677b29ea28bd6c57d Mon Sep 17 00:00:00 2001
From: Johannes Josef Junggeburth <johannes.josef.junggeburth@cern.ch>
Date: Fri, 17 Jan 2025 12:00:16 +0100
Subject: [PATCH] Add clone volume function

---
 .../GeoModelHelpers/GeoDeDuplicator.h         |  8 +++-
 .../GeoModelHelpers/src/GeoDeDuplicator.cxx   | 44 +++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/GeoModelCore/GeoModelHelpers/GeoModelHelpers/GeoDeDuplicator.h b/GeoModelCore/GeoModelHelpers/GeoModelHelpers/GeoDeDuplicator.h
index 1e0dbd8c..547252a6 100644
--- a/GeoModelCore/GeoModelHelpers/GeoModelHelpers/GeoDeDuplicator.h
+++ b/GeoModelCore/GeoModelHelpers/GeoModelHelpers/GeoDeDuplicator.h
@@ -7,6 +7,9 @@
 #include "GeoModelKernel/GeoPhysVol.h"
 #include "GeoModelKernel/GeoShape.h"
 #include "GeoModelKernel/GeoTransform.h"
+#include "GeoModelKernel/GeoAlignableTransform.h"
+#include "GeoModelKernel/GeoPhysVol.h"
+#include "GeoModelKernel/GeoFullPhysVol.h"
 #include "GeoModelKernel/GeoSerialIdentifier.h"
 #include "GeoModelKernel/GeoNameTag.h"
 #include "GeoModelKernel/GeoIdentifierTag.h"
@@ -109,6 +112,10 @@ class GeoDeDuplicator {
         /** @brief Returns a new GeoIdentifier tag */
         GeoIdPtr geoId(const int id) const;
 
+        /** @brief Clones a physical volume. All components in the tree are 
+         *         parsed through the deduplication chain */
+        PVLink clone(PVConstLink vol) const;
+
         /** @brief Toggles whether shape deduplication shall be enabled */
         void setShapeDeDuplication(bool enable);
         /** @brief Toggles whether logVol deduplication shall be enabled */
@@ -117,7 +124,6 @@ class GeoDeDuplicator {
         void setTransformDeDuplication(bool enable);
         /** @brief Toggles whether physVol node deduplication shall be enabled */
         void setPhysVolDeDuplication(bool enable);
-
         /** @brief Clears the shared Shape / Transform / SerialId & NameTag cache */
         static void clearSharedCaches();
     private:
diff --git a/GeoModelCore/GeoModelHelpers/src/GeoDeDuplicator.cxx b/GeoModelCore/GeoModelHelpers/src/GeoDeDuplicator.cxx
index f8ecad11..e4b88500 100644
--- a/GeoModelCore/GeoModelHelpers/src/GeoDeDuplicator.cxx
+++ b/GeoModelCore/GeoModelHelpers/src/GeoDeDuplicator.cxx
@@ -109,4 +109,48 @@ GeoDeDuplicator::GeoIdPtr
     GeoIdPtr newId = make_intrusive<GeoIdentifierTag>(id);
     s_geoIds.insert(std::make_pair(id, newId));
     return newId;
+}
+
+PVLink GeoDeDuplicator::clone(PVConstLink vol) const {
+    PVLink newVol{};
+    bool tryPhysVolDeDup{m_deDuplicatePhysVol};
+    GeoLogVolPtr logVol{const_cast<GeoLogVol*>(vol->getLogVol())};
+    if (dynamic_cast<const GeoPhysVol*>(vol.get())) {
+        newVol = make_intrusive<GeoPhysVol>(cacheVolume(logVol));
+    } else {
+        newVol = make_intrusive<GeoFullPhysVol>(cacheVolume(logVol));
+        tryPhysVolDeDup = false;
+    }
+    for(unsigned int chNode =0; chNode < newVol->getNChildNodes(); ++chNode) {
+        GeoIntrusivePtr<const GeoGraphNode>node{*newVol->getChildNode(chNode)};
+        /** transform nodes */
+        if (typeid(*node) == typeid(GeoAlignableTransform)) {
+            const auto geoTrf = dynamic_pointer_cast<const GeoAlignableTransform>(node);
+            newVol->add(make_intrusive<GeoAlignableTransform>(geoTrf->getDefTransform()));
+        } else if (typeid(*node) == typeid(GeoTransform)) {
+            const auto geoTrf = dynamic_pointer_cast<const GeoTransform>(node);
+            auto geoTrfNonConst = const_pointer_cast(geoTrf);
+            newVol->add(cacheTransform(geoTrfNonConst));
+        } 
+        /** physical volumes */
+        else if (auto physVol = dynamic_pointer_cast<const GeoVPhysVol>(node); physVol) {
+            newVol->add(clone(physVol));
+        } else if (auto geoId = dynamic_pointer_cast<const GeoIdentifierTag>(node); geoId) {
+            std::lock_guard guard{s_mutex};
+            newVol->add(s_geoIds.insert(std::make_pair(geoId->getIdentifier(), const_pointer_cast(geoId))).first->second);
+        } else if (auto serialId = dynamic_pointer_cast<const GeoSerialIdentifier>(node); serialId) {
+            std::lock_guard guard{s_mutex};
+            newVol->add(s_serialIds.insert(std::make_pair(serialId->getBaseId(), const_pointer_cast(serialId))).first->second);
+        } else if (auto nameTag = dynamic_pointer_cast<const GeoNameTag>(node); nameTag) {
+            std::lock_guard guard{s_mutex};
+            newVol->add(s_nameTags.insert(std::make_pair(nameTag->getName(), const_pointer_cast(nameTag))).first->second);
+        } else {
+            /// Just copy what's left
+            newVol->add(const_pointer_cast(node));
+        }
+    }
+    if (tryPhysVolDeDup){
+        newVol = cacheVolume(dynamic_pointer_cast<GeoPhysVol>(newVol));
+    }
+    return newVol;
 }
\ No newline at end of file
-- 
GitLab