Skip to content
Snippets Groups Projects
LayerStackItem.cpp 4.97 KiB
Newer Older
//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Model/Sample/LayerStackItem.cpp
//! @brief     Implements class LayerStackItem.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2024
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/Model/Sample/LayerStackItem.h"
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
#include "Base/Util/Vec.h"
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
#include "GUI/Model/Material/MaterialsSet.h"
#include "GUI/Model/Sample/LayerItem.h"
#include "GUI/Model/Util/UtilXML.h"

namespace {
namespace Tag {

const QString BaseData("BaseData");
const QString Component("Component");
const QString NumPeriods("NumPeriods");

} // namespace Tag
} // namespace

Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
LayerStackItem::LayerStackItem(const MaterialsSet* materials, uint n_periods)
    : m_n_periods(n_periods)
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    , m_materials(materials)
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    ASSERT(materials);
    m_color = QColor(220, 220, 220, 255);
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
std::vector<LayerItem*> LayerStackItem::uniqueLayerItems()
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
{
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    std::vector<LayerItem*> result;
    for (const auto& component : m_components) {
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
        std::vector<LayerItem*> sublayers = component->certainItem()->uniqueLayerItems();
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
        result.insert(result.end(), sublayers.begin(), sublayers.end());
    }
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    return result;
}

Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
std::vector<ItemWithLayers*> LayerStackItem::componentItems() const
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
{
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    std::vector<ItemWithLayers*> result;
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    for (const auto& component : m_components)
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
        result.push_back(component->certainItem());
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    return result;
}

int LayerStackItem::indexOfComponent(const ItemWithLayers* item) const
{
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    const std::vector<ItemWithLayers*> component_items = componentItems();
    return Vec::indexOfPtr(item, component_items);
LayerStackItem* LayerStackItem::parentOfComponent(const ItemWithLayers* searchedItem)
{
    for (auto* component : componentItems()) {
        if (component == searchedItem)
            return this;
        if (auto* stack = dynamic_cast<LayerStackItem*>(component)) {
            auto* subparent = stack->parentOfComponent(searchedItem);
            if (subparent)
                return subparent;
        }
    }
    return nullptr;
}

Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
ItemWithLayers* LayerStackItem::addNewItemAt(ItemWithLayers* item, int index)
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
{
    ASSERT(item);
    if (index < 0)
        index = m_components.size();

Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    auto new_item = new PolyPtr<ItemWithLayers, LayeredComponentCatalog>;
    new_item->setCertainItem(item); // gets ownership
    m_components.insert_at(index, new_item);
    return m_components[index]->certainItem();
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
LayerItem* LayerStackItem::createLayerItemAt(int index)
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
{
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    ItemWithLayers* new_item = addNewItemAt(new LayerItem(m_materials), index);
    auto* layer = dynamic_cast<LayerItem*>(new_item);
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    ASSERT(layer);
    return layer;
}

LayerStackItem* LayerStackItem::createLayerStackItemAt(int index)
{
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    ItemWithLayers* new_item = addNewItemAt(new LayerStackItem(m_materials), index);
    auto* stack = dynamic_cast<LayerStackItem*>(new_item);
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    ASSERT(stack);
    return stack;
}

void LayerStackItem::removeComponent(const ItemWithLayers* component)
{
    ASSERT(component);
    int index = indexOfComponent(component);
    ASSERT(index >= 0)
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    m_components.delete_at(index);
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
}

void LayerStackItem::moveComponent(ItemWithLayers* component, ItemWithLayers* aboveThisComponent)
{
    if (component == aboveThisComponent)
        return;

    int currentIndex = indexOfComponent(component);
    ASSERT(currentIndex >= 0);

    int abothThisIndex = indexOfComponent(aboveThisComponent);
    if (abothThisIndex < 0)
        abothThisIndex = m_components.size();

    ASSERT(currentIndex != abothThisIndex);

    auto b = m_components.begin();
    if (currentIndex < abothThisIndex)
        std::rotate(b + currentIndex, b + currentIndex + 1, b + abothThisIndex);
    else
        std::rotate(b + abothThisIndex, b + currentIndex, b + currentIndex + 1);
}

void LayerStackItem::writeTo(QXmlStreamWriter* w) const
{
    XML::writeBaseElement<ItemWithLayers>(w, Tag::BaseData, this);
    XML::writeTaggedValue(w, Tag::NumPeriods, m_n_periods);
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    for (const auto* component : m_components)
        XML::writeTaggedElement(w, Tag::Component, *component);
}

void LayerStackItem::readFrom(QXmlStreamReader* r)
{
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
    m_components.clear();
    while (r->readNextStartElement()) {
        QString tag = r->name().toString();
        if (tag == Tag::BaseData)
            XML::readBaseElement<ItemWithLayers>(r, tag, this);
        else if (tag == Tag::NumPeriods)
            m_n_periods = XML::readTaggedUInt(r, tag);
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
        else if (tag == Tag::Component) {
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
            m_components.push_back(new PolyPtr<ItemWithLayers, LayeredComponentCatalog>);
            m_components.back()->readFrom(r, m_materials);
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
            XML::gotoEndElementOfTag(r, tag);
Mikhail Svechnikov's avatar
Mikhail Svechnikov committed
        } else
            r->skipCurrentElement();
    }
}