From b3ea09228b7dbafd60db9289035af1a8f9d62b7d Mon Sep 17 00:00:00 2001
From: Matthias Puchner <github@mpuchner.de>
Date: Sun, 6 Feb 2022 09:40:08 +0100
Subject: [PATCH] make RealSpaceBuilder independent from MaterialModel

---
 GUI/View/Realspace/RealSpaceBuilder.cpp       |  4 +--
 GUI/View/Realspace/RealSpaceBuilder.h         |  2 +-
 GUI/View/Realspace/RealSpaceBuilderUtils.cpp  | 18 ++++++-------
 GUI/View/Realspace/RealSpaceBuilderUtils.h    |  7 ++---
 GUI/View/Realspace/RealSpaceCanvas.cpp        |  8 +++++-
 .../Realspace/RealSpaceMesoCrystalUtils.cpp   |  8 +++---
 .../Realspace/RealSpaceMesoCrystalUtils.h     |  6 +++--
 Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp  | 26 ++++++++++++-------
 8 files changed, 47 insertions(+), 32 deletions(-)

diff --git a/GUI/View/Realspace/RealSpaceBuilder.cpp b/GUI/View/Realspace/RealSpaceBuilder.cpp
index 090a446dd6b..f6e299d5458 100644
--- a/GUI/View/Realspace/RealSpaceBuilder.cpp
+++ b/GUI/View/Realspace/RealSpaceBuilder.cpp
@@ -63,9 +63,9 @@ std::vector<std::vector<double>> generatePositions(const ParticleLayoutItem& lay
 } // namespace
 
 
-RealSpaceBuilder::RealSpaceBuilder(const MaterialModel* materialModel)
+RealSpaceBuilder::RealSpaceBuilder(std::function<QColor(const QString&)> fnColorFromMaterialName)
 {
-    m_builderUtils = std::make_unique<RealSpace::BuilderUtils>(materialModel);
+    m_builderUtils = std::make_unique<RealSpace::BuilderUtils>(fnColorFromMaterialName);
 }
 
 void RealSpaceBuilder::populate(RealSpace::Model* model, ItemForRealSpace item,
diff --git a/GUI/View/Realspace/RealSpaceBuilder.h b/GUI/View/Realspace/RealSpaceBuilder.h
index e3e74cd3766..c2211c0cc85 100644
--- a/GUI/View/Realspace/RealSpaceBuilder.h
+++ b/GUI/View/Realspace/RealSpaceBuilder.h
@@ -41,7 +41,7 @@ public:
     using ItemForRealSpace =
         std::variant<MultiLayerItem*, LayerItem*, ParticleLayoutItem*, ItemWithParticles*>;
 
-    RealSpaceBuilder(const MaterialModel* materialModel);
+    RealSpaceBuilder(std::function<QColor(const QString&)> fnColorFromMaterialName);
 
     void populate(RealSpace::Model* model, ItemForRealSpace item,
                   const SceneGeometry& sceneGeometry,
diff --git a/GUI/View/Realspace/RealSpaceBuilderUtils.cpp b/GUI/View/Realspace/RealSpaceBuilderUtils.cpp
index 2ea80bf6019..aed949c54f2 100644
--- a/GUI/View/Realspace/RealSpaceBuilderUtils.cpp
+++ b/GUI/View/Realspace/RealSpaceBuilderUtils.cpp
@@ -15,13 +15,11 @@
 #include "GUI/View/Realspace/RealSpaceBuilderUtils.h"
 #include "Base/Const/Units.h"
 #include "Base/Util/Assert.h"
-#include "GUI/Model/Item/MaterialItem.h"
 #include "GUI/Model/Item/MesoCrystalItem.h"
 #include "GUI/Model/Item/ParticleCompositionItem.h"
 #include "GUI/Model/Item/ParticleCoreShellItem.h"
 #include "GUI/Model/Item/ParticleItem.h"
 #include "GUI/Model/Item/ParticleLayoutItem.h"
-#include "GUI/Model/Model/MaterialModel.h"
 #include "GUI/Model/Types/DoubleDescriptor.h"
 #include "GUI/View/Realspace/Particle3DContainer.h"
 #include "GUI/View/Realspace/RealSpaceBuilder.h"
@@ -56,9 +54,11 @@ R3 to_kvector(const QVector3D& origin)
 } // namespace
 
 
-GUI::RealSpace::BuilderUtils::BuilderUtils(const MaterialModel* materialModel)
-    : m_materialModel(materialModel)
+GUI::RealSpace::BuilderUtils::BuilderUtils(
+    std::function<QColor(const QString&)> fnColorFromMaterialName)
+    : m_fnColorFromMaterialName(fnColorFromMaterialName)
 {
+    ASSERT(fnColorFromMaterialName);
 }
 
 // compute cumulative abundances of particles
@@ -199,12 +199,10 @@ void GUI::RealSpace::BuilderUtils::applyParticleCoreShellTransformations(
 void GUI::RealSpace::BuilderUtils::applyParticleColor(
     const Particle& particle, GUI::RealSpace::Particles::Particle& particle3D, double alpha)
 {
-    ASSERT(m_materialModel);
     // assign correct color to the particle from the knowledge of its material
     const Material* particle_material = particle.material();
-    QString material_name = QString::fromStdString(particle_material->materialName());
-    auto* materialItem = m_materialModel->materialFromName(material_name);
-    QColor color = materialItem->color();
+    auto color =
+        m_fnColorFromMaterialName(QString::fromStdString(particle_material->materialName()));
     color.setAlphaF(alpha);
     particle3D.color = color;
 }
@@ -349,8 +347,8 @@ Particle3DContainer GUI::RealSpace::BuilderUtils::particleComposition3DContainer
 Particle3DContainer GUI::RealSpace::BuilderUtils::mesoCrystal3DContainer(
     const MesoCrystalItem& mesoCrystalItem, double total_abundance, const QVector3D& origin)
 {
-    RealSpaceMesoCrystal mesoCrystalUtils(m_materialModel, &mesoCrystalItem, total_abundance,
-                                          origin);
+    RealSpaceMesoCrystal mesoCrystalUtils(&mesoCrystalItem, total_abundance, origin,
+                                          m_fnColorFromMaterialName);
 
     Particle3DContainer mesoCrystal3DContainer = mesoCrystalUtils.populateMesoCrystal();
 
diff --git a/GUI/View/Realspace/RealSpaceBuilderUtils.h b/GUI/View/Realspace/RealSpaceBuilderUtils.h
index 564a946a4b0..c540dae1b2c 100644
--- a/GUI/View/Realspace/RealSpaceBuilderUtils.h
+++ b/GUI/View/Realspace/RealSpaceBuilderUtils.h
@@ -17,6 +17,7 @@
 
 #include "Sample/Scattering/Rotations.h"
 #include <QVector3D>
+#include <functional>
 #include <memory>
 #include <utility>
 
@@ -32,7 +33,7 @@ class ParticleLayoutItem;
 class IInterference;
 class Particle3DContainer;
 class Interference2DParaCrystal;
-class MaterialModel;
+
 namespace GUI::RealSpace {
 
 struct Vector3D;
@@ -48,7 +49,7 @@ namespace GUI::RealSpace {
 
 class BuilderUtils {
 public:
-    BuilderUtils(const MaterialModel* materialModel);
+    BuilderUtils(std::function<QColor(const QString&)> fnColorFromMaterialName);
 
     // compute cumulative abundances of particles
     QVector<double> computeCumulativeAbundances(const ParticleLayoutItem& layoutItem);
@@ -99,7 +100,7 @@ public:
                                                const QVector3D& origin = {});
 
 private:
-    const MaterialModel* m_materialModel;
+    std::function<QColor(const QString&)> m_fnColorFromMaterialName;
 };
 
 } // namespace GUI::RealSpace
diff --git a/GUI/View/Realspace/RealSpaceCanvas.cpp b/GUI/View/Realspace/RealSpaceCanvas.cpp
index 8a55508b064..11e835fd260 100644
--- a/GUI/View/Realspace/RealSpaceCanvas.cpp
+++ b/GUI/View/Realspace/RealSpaceCanvas.cpp
@@ -14,6 +14,8 @@
 
 #include "GUI/View/Realspace/RealSpaceCanvas.h"
 #include "GUI/Application/ApplicationSettings.h"
+#include "GUI/Model/Item/MaterialItem.h"
+#include "GUI/Model/Item/MultiLayerItem.h"
 #include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Model/State/SessionData.h"
 #include "GUI/View/Info/CautionSign.h"
@@ -116,7 +118,11 @@ void RealSpaceCanvas::updateScene()
 
     m_realSpaceModel = std::make_unique<GUI::RealSpace::Model>();
 
-    RealSpaceBuilder builder3D(m_materialModel);
+    const auto colorForMaterialName = [=](const QString& materialName) {
+        return m_materialModel->materialFromName(materialName)->color();
+    };
+
+    RealSpaceBuilder builder3D(colorForMaterialName);
 
     try {
         m_cautionSign->clear();
diff --git a/GUI/View/Realspace/RealSpaceMesoCrystalUtils.cpp b/GUI/View/Realspace/RealSpaceMesoCrystalUtils.cpp
index b5084dd5fc0..6981f487e68 100644
--- a/GUI/View/Realspace/RealSpaceMesoCrystalUtils.cpp
+++ b/GUI/View/Realspace/RealSpaceMesoCrystalUtils.cpp
@@ -339,14 +339,14 @@ bool isPositionInsideMesoCrystal(const IBornFF* outerShape, R3 positionInside)
 } // namespace
 
 
-RealSpaceMesoCrystal::RealSpaceMesoCrystal(const MaterialModel* materialModel,
-                                           const MesoCrystalItem* mesoCrystalItem,
-                                           double total_abundance, const QVector3D& origin)
+RealSpaceMesoCrystal::RealSpaceMesoCrystal(
+    const MesoCrystalItem* mesoCrystalItem, double total_abundance, const QVector3D& origin,
+    std::function<QColor(const QString&)> fnColorFromMaterialName)
 {
     m_mesoCrystalItem = mesoCrystalItem;
     m_total_abundance = total_abundance;
     m_origin = origin;
-    m_builderUtils = std::make_unique<GUI::RealSpace::BuilderUtils>(materialModel);
+    m_builderUtils = std::make_unique<GUI::RealSpace::BuilderUtils>(fnColorFromMaterialName);
 }
 
 Particle3DContainer RealSpaceMesoCrystal::populateMesoCrystal()
diff --git a/GUI/View/Realspace/RealSpaceMesoCrystalUtils.h b/GUI/View/Realspace/RealSpaceMesoCrystalUtils.h
index 3138f29d08d..4eed37830b1 100644
--- a/GUI/View/Realspace/RealSpaceMesoCrystalUtils.h
+++ b/GUI/View/Realspace/RealSpaceMesoCrystalUtils.h
@@ -18,6 +18,7 @@
 #include "GUI/View/Realspace/RealSpaceBuilderUtils.h"
 #include "Sample/Scattering/Rotations.h"
 #include <QVector3D>
+#include <functional>
 
 class Particle;
 class MesoCrystal;
@@ -28,8 +29,9 @@ class RealSpaceMesoCrystal {
 public:
     ~RealSpaceMesoCrystal() = default;
 
-    RealSpaceMesoCrystal(const MaterialModel* materialModel, const MesoCrystalItem* mesoCrystalItem,
-                         double total_abundance, const QVector3D& origin);
+    RealSpaceMesoCrystal(const MesoCrystalItem* mesoCrystalItem, double total_abundance,
+                         const QVector3D& origin,
+                         std::function<QColor(const QString&)> fnColorFromMaterialName);
 
     Particle3DContainer populateMesoCrystal();
 
diff --git a/Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp b/Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp
index 0b8c202be6f..4f2329da43b 100644
--- a/Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp
+++ b/Tests/Unit/GUI/TestRealSpaceBuilderUtils.cpp
@@ -1,4 +1,5 @@
 #include "GUI/Model/Item/FormFactorItems.h"
+#include "GUI/Model/Item/MaterialItem.h"
 #include "GUI/Model/Item/ParticleItem.h"
 #include "GUI/Model/Item/ParticleLayoutItem.h"
 #include "GUI/Model/Model/ApplicationModels.h"
@@ -44,9 +45,11 @@ TEST_F(TestRealSpaceBuilderUtils, computeCumulativeAbundances)
     particle1->setAbundance(8.0);
     particle2->setAbundance(2.0);
 
-    EXPECT_EQ(
-        GUI::RealSpace::BuilderUtils(&materialModel).computeCumulativeAbundances(*layout).last(),
-        10.0);
+    EXPECT_EQ(GUI::RealSpace::BuilderUtils(
+                  [&](const QString& n) { return materialModel.materialFromName(n)->color(); })
+                  .computeCumulativeAbundances(*layout)
+                  .last(),
+              10.0);
 }
 
 TEST_F(TestRealSpaceBuilderUtils, Particle3DContainer)
@@ -164,8 +167,9 @@ TEST_F(TestRealSpaceBuilderUtils, singleParticle3DContainer)
 
     // Create a 3D particle from particleItem and associate it to a Particle3DContainer object
     auto particle = particleItem->createParticle();
-    auto singleParticle3DContainer =
-        GUI::RealSpace::BuilderUtils(&materialModel).singleParticle3DContainer(*particle, 8);
+    auto singleParticle3DContainer = GUI::RealSpace::BuilderUtils([&](const QString& n) {
+                                         return materialModel.materialFromName(n)->color();
+                                     }).singleParticle3DContainer(*particle, 8);
 
     EXPECT_EQ(singleParticle3DContainer.containerSize(), 1u);
     EXPECT_EQ(singleParticle3DContainer.cumulativeAbundance(), 1);
@@ -198,16 +202,20 @@ TEST_F(TestRealSpaceBuilderUtils, particle3DContainerVector)
     particle2->setAbundance(3.0);
     particle3->setAbundance(2.0);
 
-    double total_abundance =
-        GUI::RealSpace::BuilderUtils(&materialModel).computeCumulativeAbundances(*layout).last();
+    double total_abundance = GUI::RealSpace::BuilderUtils([&](const QString& n) {
+                                 return materialModel.materialFromName(n)->color();
+                             })
+                                 .computeCumulativeAbundances(*layout)
+                                 .last();
     EXPECT_EQ(total_abundance, 10.0);
 
     particle1->setFormFactorType<BoxItem>();
     particle2->setFormFactorType<ConeItem>();
     particle3->setFormFactorType<Pyramid4Item>();
 
-    auto particle3DContainer_vector =
-        GUI::RealSpace::BuilderUtils(&materialModel).particle3DContainerVector(*layout);
+    auto particle3DContainer_vector = GUI::RealSpace::BuilderUtils([&](const QString& n) {
+                                          return materialModel.materialFromName(n)->color();
+                                      }).particle3DContainerVector(*layout);
 
     EXPECT_EQ(particle3DContainer_vector.size(), static_cast<size_t>(3));
 
-- 
GitLab