<commit_before>/**
 * @file
 * @brief Implementation of ROOT data file reader module
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "ROOTObjectReaderModule.hpp"

#include <climits>
#include <string>
#include <utility>

#include <TBranch.h>
#include <TKey.h>
#include <TObjArray.h>
#include <TTree.h>

#include "core/messenger/Messenger.hpp"
#include "core/utils/log.h"
#include "core/utils/type.h"

#include "objects/Object.hpp"
#include "objects/objects.h"

#include "core/utils/type.h"

using namespace allpix;

ROOTObjectReaderModule::ROOTObjectReaderModule(Configuration& config, Messenger* messenger, GeometryManager* geo_mgr)
    : Module(config), messenger_(messenger), geo_mgr_(geo_mgr) {}

/**
 * @note Objects cannot be stored in smart pointers due to internal ROOT logic
 */
ROOTObjectReaderModule::~ROOTObjectReaderModule() {
    for(auto message_inf : message_info_array_) {
        delete message_inf.objects;
    }
}

/**
 * Adds lambda function map to convert a vector of generic objects to a templated message containing this particular type of
 * object from its typeid.
 */
template <typename T> static void add_creator(ROOTObjectReaderModule::MessageCreatorMap& map) {
    map[typeid(T)] = [&](std::vector<Object*> objects, std::shared_ptr<Detector> detector = nullptr) {
        std::vector<T> data;
        for(auto& object : objects) {
            data.emplace_back(std::move(*static_cast<T*>(object)));
        }

        if(detector == nullptr) {
            return std::make_shared<Message<T>>(data);
        }
        return std::make_shared<Message<T>>(data, detector);
    };
}

/**
 * Uses SFINAE trick to call the add_creator function for all template arguments of a container class. Used to add creators
 * for every object in a tuple of objects.
 */
template <template <typename...> class T, typename... Args>
static void gen_creator_map_from_tag(ROOTObjectReaderModule::MessageCreatorMap& map, type_tag<T<Args...>>) {
    std::initializer_list<int> value{(add_creator<Args>(map), 0)...};
    (void)value;
}

/**
 * Wrapper function to make the SFINAE trick in \ref gen_creator_map_from_tag work.
 */
template <typename T> static ROOTObjectReaderModule::MessageCreatorMap gen_creator_map() {
    ROOTObjectReaderModule::MessageCreatorMap ret_map;
    gen_creator_map_from_tag(ret_map, type_tag<T>());
    return ret_map;
}

void ROOTObjectReaderModule::init() {
    // Read include and exclude list
    if(config_.has("include") && config_.has("exclude")) {
        throw InvalidCombinationError(
            config_, {"exclude", "include"}, "include and exclude parameter are mutually exclusive");
    } else if(config_.has("include")) {
        auto inc_arr = config_.getArray<std::string>("include");
        include_.insert(inc_arr.begin(), inc_arr.end());
    } else if(config_.has("exclude")) {
        auto exc_arr = config_.getArray<std::string>("exclude");
        exclude_.insert(exc_arr.begin(), exc_arr.end());
    }

    // Initialize the call map from the tuple of available objects
    message_creator_map_ = gen_creator_map<allpix::OBJECTS>();

    // Open the file with the objects
    input_file_ = std::make_unique<TFile>(config_.getPath("file_name", true).c_str());

    // Read all the trees in the file
    TList* keys = input_file_->GetListOfKeys();
    std::set<std::string> tree_names;

    for(auto&& object : *keys) {
        auto& key = dynamic_cast<TKey&>(*object);
        if(std::string(key.GetClassName()) == "TTree") {
            auto tree = static_cast<TTree*>(key.ReadObjectAny(nullptr));

            // Check if a version of this tree has already been read
            if(tree_names.find(tree->GetName()) != tree_names.end()) {
                LOG(TRACE) << "Skipping copy of tree with name " << tree->GetName()
                           << " because one with identical name has already been processed";
                continue;
            }
            tree_names.insert(tree->GetName());

            // Check if this tree should be used
            if((!include_.empty() && include_.find(tree->GetName()) == include_.end()) ||
               (!exclude_.empty() && exclude_.find(tree->GetName()) != exclude_.end())) {
                LOG(TRACE) << "Ignoring tree with " << tree->GetName()
                           << " objects because it has been excluded or not explicitly included";
                continue;
            }

            trees_.push_back(tree);
        }
    }

    if(trees_.empty()) {
        LOG(ERROR) << "Provided ROOT file does not contain any trees, module will not read any data";
    }

    // Loop over all found trees
    for(auto& tree : trees_) {
        // Loop over the list of branches and create the set of receiver objects
        TObjArray* branches = tree->GetListOfBranches();
        for(int i = 0; i < branches->GetEntries(); i++) {
            auto* branch = static_cast<TBranch*>(branches->At(i));

            // Add a new vector of objects and bind it to the branch
            message_info message_inf;
            message_inf.objects = new std::vector<Object*>;
            message_info_array_.emplace_back(message_inf);
            branch->SetAddress(&(message_info_array_.back().objects));

            // Fill the rest of the message information
            // FIXME: we want to index this in a different way
            std::string branch_name = branch->GetName();
            auto split = allpix::split<std::string>(branch_name, "_");

            // Fetch information from the tree name
            size_t expected_size = 2;
            size_t det_idx = 0;
            size_t name_idx = 1;
            if(branch_name.front() == '_' || branch_name.empty()) {
                --expected_size;
                det_idx = INT_MAX;
                --name_idx;
            }
            if(branch_name.find('_') == std::string::npos) {
                --expected_size;
                name_idx = INT_MAX;
            }

            // Check tree structure and if object type matches name
            auto split_type = allpix::split<std::string>(branch->GetClassName(), "<>");
            if(expected_size != split.size() || split_type.size() != 2 || split_type[1].size() <= 2) {
                throw ModuleError("Tree is malformed and cannot be used for creating messages");
            }
            std::string class_name = split_type[1].substr(0, split_type[1].size() - 1);
            std::string apx_namespace = "allpix::";
            size_t ap_idx = class_name.find(apx_namespace);
            if(ap_idx != std::string::npos) {
                class_name.replace(ap_idx, apx_namespace.size(), "");
            }
            if(class_name != tree->GetName()) {
                throw ModuleError("Tree contains objects of the wrong type");
            }

            if(name_idx != INT_MAX) {
                message_info_array_.back().name = split[name_idx];
            }
            std::shared_ptr<Detector> detector = nullptr;
            if(det_idx != INT_MAX) {
                message_info_array_.back().detector = geo_mgr_->getDetector(split[det_idx]);
            }
        }
    }
}

void ROOTObjectReaderModule::run(unsigned int event_num) {
    --event_num;
    for(auto& tree : trees_) {
        if(event_num >= tree->GetEntries()) {
            throw EndOfRunException("Requesting end of run because TTree only contains data for " +
                                    std::to_string(event_num) + " events");
        }
        tree->GetEntry(event_num);
    }
    LOG(TRACE) << "Building messages from stored objects";

    // Loop through all branches
    for(auto message_inf : message_info_array_) {
        auto objects = message_inf.objects;

        // Skip empty objects in current event
        if(objects->empty()) {
            continue;
        }

        // Check if a pointer to a dispatcher method exist
        auto first_object = (*objects)[0];
        auto iter = message_creator_map_.find(typeid(*first_object));
        if(iter == message_creator_map_.end()) {
            LOG(INFO) << "Cannot dispatch message with object " << allpix::demangle(typeid(*first_object).name())
                      << " because it not registered for messaging";
            continue;
        }

        // Update statistics
        read_cnt_ += objects->size();

        // Create a message
        std::shared_ptr<BaseMessage> message = iter->second(*objects, message_inf.detector);

        // Dispatch the message
        messenger_->dispatchMessage(this, message, message_inf.name);
    }
}

void ROOTObjectReaderModule::finalize() {
    int branch_count = 0;
    for(auto& tree : trees_) {
        branch_count += tree->GetListOfBranches()->GetEntries();
    }

    // Print statistics
    LOG(INFO) << "Read " << read_cnt_ << " objects from " << branch_count << " branches";

    // Close the file
    input_file_->Close();
}
<commit_msg>ROOTObjectReader: Compare random_seed_core between global config and input data This fixes #105<commit_after>/**
 * @file
 * @brief Implementation of ROOT data file reader module
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "ROOTObjectReaderModule.hpp"

#include <climits>
#include <string>
#include <utility>

#include <TBranch.h>
#include <TKey.h>
#include <TObjArray.h>
#include <TTree.h>

#include "core/messenger/Messenger.hpp"
#include "core/utils/log.h"
#include "core/utils/type.h"

#include "objects/Object.hpp"
#include "objects/objects.h"

#include "core/utils/type.h"

using namespace allpix;

ROOTObjectReaderModule::ROOTObjectReaderModule(Configuration& config, Messenger* messenger, GeometryManager* geo_mgr)
    : Module(config), messenger_(messenger), geo_mgr_(geo_mgr) {}

/**
 * @note Objects cannot be stored in smart pointers due to internal ROOT logic
 */
ROOTObjectReaderModule::~ROOTObjectReaderModule() {
    for(auto message_inf : message_info_array_) {
        delete message_inf.objects;
    }
}

/**
 * Adds lambda function map to convert a vector of generic objects to a templated message containing this particular type of
 * object from its typeid.
 */
template <typename T> static void add_creator(ROOTObjectReaderModule::MessageCreatorMap& map) {
    map[typeid(T)] = [&](std::vector<Object*> objects, std::shared_ptr<Detector> detector = nullptr) {
        std::vector<T> data;
        for(auto& object : objects) {
            data.emplace_back(std::move(*static_cast<T*>(object)));
        }

        if(detector == nullptr) {
            return std::make_shared<Message<T>>(data);
        }
        return std::make_shared<Message<T>>(data, detector);
    };
}

/**
 * Uses SFINAE trick to call the add_creator function for all template arguments of a container class. Used to add creators
 * for every object in a tuple of objects.
 */
template <template <typename...> class T, typename... Args>
static void gen_creator_map_from_tag(ROOTObjectReaderModule::MessageCreatorMap& map, type_tag<T<Args...>>) {
    std::initializer_list<int> value{(add_creator<Args>(map), 0)...};
    (void)value;
}

/**
 * Wrapper function to make the SFINAE trick in \ref gen_creator_map_from_tag work.
 */
template <typename T> static ROOTObjectReaderModule::MessageCreatorMap gen_creator_map() {
    ROOTObjectReaderModule::MessageCreatorMap ret_map;
    gen_creator_map_from_tag(ret_map, type_tag<T>());
    return ret_map;
}

void ROOTObjectReaderModule::init() {
    // Read include and exclude list
    if(config_.has("include") && config_.has("exclude")) {
        throw InvalidCombinationError(
            config_, {"exclude", "include"}, "include and exclude parameter are mutually exclusive");
    } else if(config_.has("include")) {
        auto inc_arr = config_.getArray<std::string>("include");
        include_.insert(inc_arr.begin(), inc_arr.end());
    } else if(config_.has("exclude")) {
        auto exc_arr = config_.getArray<std::string>("exclude");
        exclude_.insert(exc_arr.begin(), exc_arr.end());
    }

    // Initialize the call map from the tuple of available objects
    message_creator_map_ = gen_creator_map<allpix::OBJECTS>();

    // Open the file with the objects
    input_file_ = std::make_unique<TFile>(config_.getPath("file_name", true).c_str());

    // Read all the trees in the file
    TList* keys = input_file_->GetListOfKeys();
    std::set<std::string> tree_names;

    for(auto&& object : *keys) {
        auto& key = dynamic_cast<TKey&>(*object);
        if(std::string(key.GetClassName()) == "TTree") {
            auto tree = static_cast<TTree*>(key.ReadObjectAny(nullptr));

            // Check if a version of this tree has already been read
            if(tree_names.find(tree->GetName()) != tree_names.end()) {
                LOG(TRACE) << "Skipping copy of tree with name " << tree->GetName()
                           << " because one with identical name has already been processed";
                continue;
            }
            tree_names.insert(tree->GetName());

            // Check if this tree should be used
            if((!include_.empty() && include_.find(tree->GetName()) == include_.end()) ||
               (!exclude_.empty() && exclude_.find(tree->GetName()) != exclude_.end())) {
                LOG(TRACE) << "Ignoring tree with " << tree->GetName()
                           << " objects because it has been excluded or not explicitly included";
                continue;
            }

            trees_.push_back(tree);
        }
    }

    if(trees_.empty()) {
        LOG(ERROR) << "Provided ROOT file does not contain any trees, module will not read any data";
    }

    // Cross-check the core random seed stored in the file with the one configured:
    auto global_config = getConfigManager()->getGlobalConfiguration();
    auto config_seed = global_config.get<uint64_t>("random_seed_core");

    std::string* str;
    input_file_->GetObject("config/Allpix/random_seed_core", str);
    if(!str) {
        throw InvalidValueError(global_config,
                                "random_seed_core",
                                "no random seed for core set in the input data file, cross-check with configured value "
                                "impossible - this might lead to unexpected behavior.");
    }

    auto file_seed = allpix::from_string<uint64_t>(*str);
    if(config_seed != file_seed) {
        throw InvalidValueError(global_config,
                                "random_seed_core",
                                "mismatch between core random seed in configuration file and input data - this "
                                "might lead to unexpected behavior. Set to value configured in the input data file: " +
                                    (*str));
    }

    // Loop over all found trees
    for(auto& tree : trees_) {
        // Loop over the list of branches and create the set of receiver objects
        TObjArray* branches = tree->GetListOfBranches();
        for(int i = 0; i < branches->GetEntries(); i++) {
            auto* branch = static_cast<TBranch*>(branches->At(i));

            // Add a new vector of objects and bind it to the branch
            message_info message_inf;
            message_inf.objects = new std::vector<Object*>;
            message_info_array_.emplace_back(message_inf);
            branch->SetAddress(&(message_info_array_.back().objects));

            // Fill the rest of the message information
            // FIXME: we want to index this in a different way
            std::string branch_name = branch->GetName();
            auto split = allpix::split<std::string>(branch_name, "_");

            // Fetch information from the tree name
            size_t expected_size = 2;
            size_t det_idx = 0;
            size_t name_idx = 1;
            if(branch_name.front() == '_' || branch_name.empty()) {
                --expected_size;
                det_idx = INT_MAX;
                --name_idx;
            }
            if(branch_name.find('_') == std::string::npos) {
                --expected_size;
                name_idx = INT_MAX;
            }

            // Check tree structure and if object type matches name
            auto split_type = allpix::split<std::string>(branch->GetClassName(), "<>");
            if(expected_size != split.size() || split_type.size() != 2 || split_type[1].size() <= 2) {
                throw ModuleError("Tree is malformed and cannot be used for creating messages");
            }
            std::string class_name = split_type[1].substr(0, split_type[1].size() - 1);
            std::string apx_namespace = "allpix::";
            size_t ap_idx = class_name.find(apx_namespace);
            if(ap_idx != std::string::npos) {
                class_name.replace(ap_idx, apx_namespace.size(), "");
            }
            if(class_name != tree->GetName()) {
                throw ModuleError("Tree contains objects of the wrong type");
            }

            if(name_idx != INT_MAX) {
                message_info_array_.back().name = split[name_idx];
            }
            std::shared_ptr<Detector> detector = nullptr;
            if(det_idx != INT_MAX) {
                message_info_array_.back().detector = geo_mgr_->getDetector(split[det_idx]);
            }
        }
    }
}

void ROOTObjectReaderModule::run(unsigned int event_num) {
    --event_num;
    for(auto& tree : trees_) {
        if(event_num >= tree->GetEntries()) {
            throw EndOfRunException("Requesting end of run because TTree only contains data for " +
                                    std::to_string(event_num) + " events");
        }
        tree->GetEntry(event_num);
    }
    LOG(TRACE) << "Building messages from stored objects";

    // Loop through all branches
    for(auto message_inf : message_info_array_) {
        auto objects = message_inf.objects;

        // Skip empty objects in current event
        if(objects->empty()) {
            continue;
        }

        // Check if a pointer to a dispatcher method exist
        auto first_object = (*objects)[0];
        auto iter = message_creator_map_.find(typeid(*first_object));
        if(iter == message_creator_map_.end()) {
            LOG(INFO) << "Cannot dispatch message with object " << allpix::demangle(typeid(*first_object).name())
                      << " because it not registered for messaging";
            continue;
        }

        // Update statistics
        read_cnt_ += objects->size();

        // Create a message
        std::shared_ptr<BaseMessage> message = iter->second(*objects, message_inf.detector);

        // Dispatch the message
        messenger_->dispatchMessage(this, message, message_inf.name);
    }
}

void ROOTObjectReaderModule::finalize() {
    int branch_count = 0;
    for(auto& tree : trees_) {
        branch_count += tree->GetListOfBranches()->GetEntries();
    }

    // Print statistics
    LOG(INFO) << "Read " << read_cnt_ << " objects from " << branch_count << " branches";

    // Close the file
    input_file_->Close();
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "qt/pivx/settings/settingsbackupwallet.h"
#include "qt/pivx/settings/forms/ui_settingsbackupwallet.h"
#include <QFile>
#include <QGraphicsDropShadowEffect>
#include "guiutil.h"
#include "qt/pivx/qtutils.h"
#include "guiinterface.h"
#include "qt/pivx/qtutils.h"
SettingsBackupWallet::SettingsBackupWallet(PIVXGUI* _window, QWidget *parent) :
    PWidget(_window, parent),
    ui(new Ui::SettingsBackupWallet)
{
    ui->setupUi(this);

    this->setStyleSheet(parent->styleSheet());

    /* Containers */
    ui->left->setProperty("cssClass", "container");
    ui->left->setContentsMargins(10,10,10,10);

    // Title
    ui->labelTitle->setText(tr("Backup Wallet "));
    ui->labelTitle->setProperty("cssClass", "text-title-screen");

    ui->labelTitle_2->setText(tr("Change Wallet Passphrase"));
    ui->labelTitle_2->setProperty("cssClass", "text-title-screen");
    ui->labelDivider->setProperty("cssClass", "container-divider");

    // Subtitle
    ui->labelSubtitle1->setText(tr("Keep your wallet safe doing regular backups, store your backup file externally.\nThis option creates a wallet.dat file that can be used to recover your whole balance (transactions and addresses) from another device."));
    ui->labelSubtitle1->setProperty("cssClass", "text-subtitle");

    ui->labelSubtitle_2->setText(tr("Change your wallet encryption passphrase for another one that you like. This will decrypt and encrypt your whole data under the new passphrase.\nRemember to write it down to not lose access to your funds."));
    ui->labelSubtitle_2->setProperty("cssClass", "text-subtitle");

    // Location
    ui->labelSubtitleLocation->setText(tr("Where"));
    ui->labelSubtitleLocation->setProperty("cssClass", "text-title");

    ui->pushButtonDocuments->setText(tr("Set a folder location"));
    ui->pushButtonDocuments->setProperty("cssClass", "btn-edit-primary-folder");
    setShadow(ui->pushButtonDocuments);

    // Buttons
    ui->pushButtonSave->setText(tr("Backup"));
    setCssBtnPrimary(ui->pushButtonSave);

    ui->pushButtonSave_2->setText(tr("Change Passphrase"));
    setCssBtnPrimary(ui->pushButtonSave_2);

    connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(backupWallet()));
    connect(ui->pushButtonDocuments, SIGNAL(clicked()), this, SLOT(selectFileOutput()));
    connect(ui->pushButtonSave_2, SIGNAL(clicked()), this, SLOT(changePassphrase()));
}

void SettingsBackupWallet::selectFileOutput()
{
    QString filenameRet = GUIUtil::getSaveFileName(this,
                                        tr("Backup Wallet"), QString(),
                                        tr("Wallet Data (*.dat)"), NULL);

    if (!filenameRet.isEmpty()) {
        filename = filenameRet;
        ui->pushButtonDocuments->setText(filename);
    }
}

void SettingsBackupWallet::backupWallet()
{
    if(walletModel && !filename.isEmpty()) {
        inform(walletModel->backupWallet(filename) ? tr("Backup created") : tr("Backup creation failed"));
        filename = QString();
        ui->pushButtonDocuments->setText(tr("Set a folder location"));
    } else {
        inform(tr("Please select a folder to export the backup first."));
    }
}

void SettingsBackupWallet::changePassphrase()
{
    showHideOp(true);
    AskPassphraseDialog *dlg = nullptr;
    if (walletModel->getEncryptionStatus() == WalletModel::Unencrypted) {
        dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::Encrypt, window,
                walletModel, AskPassphraseDialog::Context::Encrypt);
    } else {
        dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::ChangePass, window,
                walletModel, AskPassphraseDialog::Context::ChangePass);
    }
    dlg->adjustSize();
    emit execDialog(dlg);
    dlg->deleteLater();
}

SettingsBackupWallet::~SettingsBackupWallet()
{
    delete ui;
}
<commit_msg>Rewording text under Change Wallet Passphrase<commit_after>// Copyright (c) 2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "qt/pivx/settings/settingsbackupwallet.h"
#include "qt/pivx/settings/forms/ui_settingsbackupwallet.h"
#include <QFile>
#include <QGraphicsDropShadowEffect>
#include "guiutil.h"
#include "qt/pivx/qtutils.h"
#include "guiinterface.h"
#include "qt/pivx/qtutils.h"
SettingsBackupWallet::SettingsBackupWallet(PIVXGUI* _window, QWidget *parent) :
    PWidget(_window, parent),
    ui(new Ui::SettingsBackupWallet)
{
    ui->setupUi(this);

    this->setStyleSheet(parent->styleSheet());

    /* Containers */
    ui->left->setProperty("cssClass", "container");
    ui->left->setContentsMargins(10,10,10,10);

    // Title
    ui->labelTitle->setText(tr("Backup Wallet "));
    ui->labelTitle->setProperty("cssClass", "text-title-screen");

    ui->labelTitle_2->setText(tr("Change Wallet Passphrase"));
    ui->labelTitle_2->setProperty("cssClass", "text-title-screen");
    ui->labelDivider->setProperty("cssClass", "container-divider");

    // Subtitle
    ui->labelSubtitle1->setText(tr("Keep your wallet safe doing regular backups, store your backup file externally.\nThis option creates a wallet.dat file that can be used to recover your whole balance (transactions and addresses) from another device."));
    ui->labelSubtitle1->setProperty("cssClass", "text-subtitle");

    ui->labelSubtitle_2->setText(tr("This will decrypt the whole wallet data and encrypt it back with the new passphrase.\nRemember to write it down and store it safely, otherwise you might lose access to your funds."));
    ui->labelSubtitle_2->setProperty("cssClass", "text-subtitle");

    // Location
    ui->labelSubtitleLocation->setText(tr("Where"));
    ui->labelSubtitleLocation->setProperty("cssClass", "text-title");

    ui->pushButtonDocuments->setText(tr("Set a folder location"));
    ui->pushButtonDocuments->setProperty("cssClass", "btn-edit-primary-folder");
    setShadow(ui->pushButtonDocuments);

    // Buttons
    ui->pushButtonSave->setText(tr("Backup"));
    setCssBtnPrimary(ui->pushButtonSave);

    ui->pushButtonSave_2->setText(tr("Change Passphrase"));
    setCssBtnPrimary(ui->pushButtonSave_2);

    connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(backupWallet()));
    connect(ui->pushButtonDocuments, SIGNAL(clicked()), this, SLOT(selectFileOutput()));
    connect(ui->pushButtonSave_2, SIGNAL(clicked()), this, SLOT(changePassphrase()));
}

void SettingsBackupWallet::selectFileOutput()
{
    QString filenameRet = GUIUtil::getSaveFileName(this,
                                        tr("Backup Wallet"), QString(),
                                        tr("Wallet Data (*.dat)"), NULL);

    if (!filenameRet.isEmpty()) {
        filename = filenameRet;
        ui->pushButtonDocuments->setText(filename);
    }
}

void SettingsBackupWallet::backupWallet()
{
    if(walletModel && !filename.isEmpty()) {
        inform(walletModel->backupWallet(filename) ? tr("Backup created") : tr("Backup creation failed"));
        filename = QString();
        ui->pushButtonDocuments->setText(tr("Set a folder location"));
    } else {
        inform(tr("Please select a folder to export the backup first."));
    }
}

void SettingsBackupWallet::changePassphrase()
{
    showHideOp(true);
    AskPassphraseDialog *dlg = nullptr;
    if (walletModel->getEncryptionStatus() == WalletModel::Unencrypted) {
        dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::Encrypt, window,
                walletModel, AskPassphraseDialog::Context::Encrypt);
    } else {
        dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::ChangePass, window,
                walletModel, AskPassphraseDialog::Context::ChangePass);
    }
    dlg->adjustSize();
    emit execDialog(dlg);
    dlg->deleteLater();
}

SettingsBackupWallet::~SettingsBackupWallet()
{
    delete ui;
}
<|endoftext|>


<commit_before>#ifndef TYPES_H
#define TYPES_H
/*
Defines a set of types for use on the hl-side.
*/

#include<cstring>
#include"objects.hpp"

class GenericTraverser {
public:
	virtual void traverse(Object::ref&) =0;
	virtual ~GenericTraverser();
};

/*-----------------------------------------------------------------------------
Generic
-----------------------------------------------------------------------------*/

class Generic {
public:

	virtual void traverse_references(GenericTraverser* gt) {
		/*default to having no references to traverse*/
		/*example for Cons:
		gt->traverse(a);
		gt->traverse(d);
		*/
	}

	/*some objects have extra allocated space at their ends
	(e.g. Closure).
 	This virtual function returns the total size of the class
	plus extra allocated space.
	*/
	virtual size_t real_size(void) const =0;

	/*hash functions for table-ident and table-is*/
	virtual size_t hash_ident(void) const {
		return reinterpret_cast<size_t>(this);
	}
	virtual size_t hash_is(void) const {
		return reinterpret_cast<size_t>(this);
	}

	/*broken hearts for GC*/
	virtual void break_heart(Generic*) =0;

	/*dtor*/
	virtual ~Generic() { }
};

/*-----------------------------------------------------------------------------
Broken Heart tags
-----------------------------------------------------------------------------*/

void throw_OverBrokenHeart(Generic*);

class BrokenHeart : public Generic {
private:
	// disallowed
	BrokenHeart();
	BrokenHeart(BrokenHeart const&);
public:
	Generic* to;
	virtual void break_heart(Generic* to) {
		/*already broken - don't break too much!*/
		throw_OverBrokenHeart(to);
	}
	BrokenHeart(Generic* nto) : to(nto) { }
};

class BrokenHeartVariadic : public BrokenHeart {
private:
	// disallowed
	BrokenHeartVariadic();
	BrokenHeartVariadic(BrokenHeart const&);
protected:
	size_t sz;
public:
	/*exists only for RTTI*/
	virtual void break_heart(Generic* to) {
		throw_OverBrokenHeart(to);
	}
	BrokenHeartVariadic(Generic* x, size_t nsz)
		: BrokenHeart(x), sz(nsz) { }
};

template<class T>
class BrokenHeartFor : public BrokenHeart {
private:
	// disallowed
	BrokenHeartFor<T>();
	BrokenHeartFor<T>(BrokenHeartFor<T> const&);
public:
	virtual size_t real_size(void) const {
		return Object::round_up_to_alignment(sizeof(T));
	}
	explicit BrokenHeartFor<T>(Generic* x) : BrokenHeart(x) { }
};

template<class T>
class BrokenHeartForVariadic : public BrokenHeartVariadic {
private:
	// disallowed
	BrokenHeartForVariadic<T>();
	BrokenHeartForVariadic<T>(BrokenHeartForVariadic<T> const&);
public:
	virtual size_t real_size(void) const {
		return Object::round_up_to_alignment(sizeof(T))
			 + Object::round_up_to_alignment(
				sz * sizeof(Object::ref)
			)
		;
	}
	BrokenHeartForVariadic<T>(Generic* x, size_t nsz)
		: BrokenHeartVariadic(x, nsz) { }
};

/*-----------------------------------------------------------------------------
Base classes for Generic-derived objects
-----------------------------------------------------------------------------*/

template<class T>
class GenericDerived : public Generic {
protected:
	GenericDerived<T>(void) { }
public:
	virtual size_t real_size(void) const {
		return Object::round_up_to_alignment(sizeof(T));
	}
	virtual void break_heart(Generic* to) {
		Generic* gp = this;
		gp->~Generic();
		new((void*) gp) BrokenHeartFor<T>(to);
	};
};

/*This class implements a variable-size object by informing the
memory system to reserve extra space.
Note that classes which derive from this should provide
a factory function!
*/
template<class T>
class GenericDerivedVariadic : public Generic {
	GenericDerivedVariadic<T>(void); // disallowed!
protected:
	/*number of extra Object::ref's*/
	size_t sz;
	/*used by the derived classes to get access to
	the variadic data at the end of the object.
	*/
	inline Object::ref& index(size_t i) {
		void* vp = this;
		char* cp = (char*) vp;
		cp = cp + sizeof(T);
		Object::ref* op = (void*) cp;
		return op[i];
	}
	explicit GenericDerivedVariadic<T>(size_t nsz) : sz(nsz) {
		/*clear the extra references*/
		for(size_t i; i < nsz; ++i) {
			index(i) = Object::nil();
		}
	}
public:
	virtual size_t real_size(void) const {
		return Object::round_up_to_alignment(sizeof(T))
			 + Object::round_up_to_alignment(
				sz * sizeof(Object::ref)
			)
		;
	}
	virtual void break_heart(Object::ref to) {
		Generic* gp = this;
		size_t nsz = sz; //save this before dtoring!
		gp->~Generic();
		new((void*) gp) BrokenHeartForVariadic<T>(to, nsz);
	}
};

/*-----------------------------------------------------------------------------
Utility
-----------------------------------------------------------------------------*/

void throw_HlError(char const*);

/*Usage:
Cons* cp = expect_type<Cons>(proc.stack().top(),
		"Your mom expects a Cons cell on top"
);
*/
template<class T>
static inline T* expect_type(Object::ref x, char const* error) {
	if(!is_a<Generic*>(x)) throw_HlError(error);
	T* tmp = dynamic_cast<T*>(as_a<Generic*>(x));
	if(!tmp) throw_HlError(error);
	return tmp;
}

/*
 * Cons cell
 */

class Cons : public GenericDerived<Cons> {
private:

  Object::ref car_ref;
  Object::ref cdr_ref;

public:

  inline Object::ref car() { return car_ref; }
  inline Object::ref cdr() { return cdr_ref; }

  Cons() : car_ref(Object::nil()), cdr_ref(Object::nil()) {}

  void traverse_references(GenericTraverser *gt) {
    gt->traverse(car_ref);
    gt->traverse(cdr_ref);
  }
};

static inline Object::ref car(Object::ref x) {
	if(!x) return x;
	return expect_type<Cons>(x,"'car expects a Cons cell")->car();
}
static inline Object::ref cdr(Object::ref x) {
	if(!x) return x;
	return expect_type<Cons>(x,"'cdr expects a Cons cell")->cdr();
}

#endif //TYPES_H
<commit_msg>inc/types.hpp: Added warning regarding ctors for Generic-derived objects, added scar/scdr<commit_after>#ifndef TYPES_H
#define TYPES_H
/*
Defines a set of types for use on the hl-side.
*/

#include<cstring>
#include"objects.hpp"

class GenericTraverser {
public:
	virtual void traverse(Object::ref&) =0;
	virtual ~GenericTraverser();
};

/*-----------------------------------------------------------------------------
Generic
-----------------------------------------------------------------------------*/

class Generic {
public:

	virtual void traverse_references(GenericTraverser* gt) {
		/*default to having no references to traverse*/
		/*example for Cons:
		gt->traverse(a);
		gt->traverse(d);
		*/
	}

	/*some objects have extra allocated space at their ends
	(e.g. Closure).
 	This virtual function returns the total size of the class
	plus extra allocated space.
	*/
	virtual size_t real_size(void) const =0;

	/*hash functions for table-ident and table-is*/
	virtual size_t hash_ident(void) const {
		return reinterpret_cast<size_t>(this);
	}
	virtual size_t hash_is(void) const {
		return reinterpret_cast<size_t>(this);
	}

	/*broken hearts for GC*/
	virtual void break_heart(Generic*) =0;

	/*dtor*/
	virtual ~Generic() { }
};

/*-----------------------------------------------------------------------------
Broken Heart tags
-----------------------------------------------------------------------------*/

void throw_OverBrokenHeart(Generic*);

class BrokenHeart : public Generic {
private:
	// disallowed
	BrokenHeart();
	BrokenHeart(BrokenHeart const&);
public:
	Generic* to;
	virtual void break_heart(Generic* to) {
		/*already broken - don't break too much!*/
		throw_OverBrokenHeart(to);
	}
	BrokenHeart(Generic* nto) : to(nto) { }
};

class BrokenHeartVariadic : public BrokenHeart {
private:
	// disallowed
	BrokenHeartVariadic();
	BrokenHeartVariadic(BrokenHeart const&);
protected:
	size_t sz;
public:
	/*exists only for RTTI*/
	virtual void break_heart(Generic* to) {
		throw_OverBrokenHeart(to);
	}
	BrokenHeartVariadic(Generic* x, size_t nsz)
		: BrokenHeart(x), sz(nsz) { }
};

template<class T>
class BrokenHeartFor : public BrokenHeart {
private:
	// disallowed
	BrokenHeartFor<T>();
	BrokenHeartFor<T>(BrokenHeartFor<T> const&);
public:
	virtual size_t real_size(void) const {
		return Object::round_up_to_alignment(sizeof(T));
	}
	explicit BrokenHeartFor<T>(Generic* x) : BrokenHeart(x) { }
};

template<class T>
class BrokenHeartForVariadic : public BrokenHeartVariadic {
private:
	// disallowed
	BrokenHeartForVariadic<T>();
	BrokenHeartForVariadic<T>(BrokenHeartForVariadic<T> const&);
public:
	virtual size_t real_size(void) const {
		return Object::round_up_to_alignment(sizeof(T))
			 + Object::round_up_to_alignment(
				sz * sizeof(Object::ref)
			)
		;
	}
	BrokenHeartForVariadic<T>(Generic* x, size_t nsz)
		: BrokenHeartVariadic(x, nsz) { }
};

/*-----------------------------------------------------------------------------
Base classes for Generic-derived objects
-----------------------------------------------------------------------------*/

template<class T>
class GenericDerived : public Generic {
protected:
	GenericDerived<T>(void) { }
public:
	virtual size_t real_size(void) const {
		return Object::round_up_to_alignment(sizeof(T));
	}
	virtual void break_heart(Generic* to) {
		Generic* gp = this;
		gp->~Generic();
		new((void*) gp) BrokenHeartFor<T>(to);
	};
};

/*This class implements a variable-size object by informing the
memory system to reserve extra space.
Note that classes which derive from this should provide
a factory function!
*/
template<class T>
class GenericDerivedVariadic : public Generic {
	GenericDerivedVariadic<T>(void); // disallowed!
protected:
	/*number of extra Object::ref's*/
	size_t sz;
	/*used by the derived classes to get access to
	the variadic data at the end of the object.
	*/
	inline Object::ref& index(size_t i) {
		void* vp = this;
		char* cp = (char*) vp;
		cp = cp + sizeof(T);
		Object::ref* op = (void*) cp;
		return op[i];
	}
	explicit GenericDerivedVariadic<T>(size_t nsz) : sz(nsz) {
		/*clear the extra references*/
		for(size_t i; i < nsz; ++i) {
			index(i) = Object::nil();
		}
	}
public:
	virtual size_t real_size(void) const {
		return Object::round_up_to_alignment(sizeof(T))
			 + Object::round_up_to_alignment(
				sz * sizeof(Object::ref)
			)
		;
	}
	virtual void break_heart(Object::ref to) {
		Generic* gp = this;
		size_t nsz = sz; //save this before dtoring!
		gp->~Generic();
		new((void*) gp) BrokenHeartForVariadic<T>(to, nsz);
	}
};

/*-----------------------------------------------------------------------------
Utility
-----------------------------------------------------------------------------*/

void throw_HlError(char const*);

/*Usage:
Cons* cp = expect_type<Cons>(proc.stack().top(),
		"Your mom expects a Cons cell on top"
);
*/
template<class T>
static inline T* expect_type(Object::ref x, char const* error) {
	if(!is_a<Generic*>(x)) throw_HlError(error);
	T* tmp = dynamic_cast<T*>(as_a<Generic*>(x));
	if(!tmp) throw_HlError(error);
	return tmp;
}

/*
 * Cons cell
 */

class Cons : public GenericDerived<Cons> {
private:

  Object::ref car_ref;
  Object::ref cdr_ref;

public:

  inline Object::ref car() { return car_ref; }
  inline Object::ref cdr() { return cdr_ref; }
  inline Object::ref scar(Object::ref x) { return car_ref = x; }
  inline Object::ref scdr(Object::ref x) { return cdr_ref = x; }

  Cons() : car_ref(Object::nil()), cdr_ref(Object::nil()) {}
  /*
   * Note that we *can't* safely construct any heap-based objects
   * by, say, passing them any of their data.  This is because the
   * act of allocating space for these objects may start a garbage
   * collection, which can move *other* objects.  So any references
   * passed into the constructor will be invalid; instead, the
   * process must save the data to be put in the new object in a
   * root location (such as the process stack) and after it is
   * given the newly-constructed object, it must store the data
   * straight from the root location.
   */

  void traverse_references(GenericTraverser *gt) {
    gt->traverse(car_ref);
    gt->traverse(cdr_ref);
  }
};

static inline Object::ref car(Object::ref x) {
	if(!x) return x;
	return expect_type<Cons>(x,"'car expects a Cons cell")->car();
}
static inline Object::ref cdr(Object::ref x) {
	if(!x) return x;
	return expect_type<Cons>(x,"'cdr expects a Cons cell")->cdr();
}
static inline Object::ref scar(Object::ref c, Object::ref v) {
	return expect_type<Cons>(c,"'scar expects a true Cons cell")->scar(v);
}
static inline Object::ref scdr(Object::ref c, Object::ref v) {
	return expect_type<Cons>(c,"'scdr expects a true Cons cell")->scdr(v);
}

#endif //TYPES_H
<|endoftext|>


<commit_before>#include "generated_nrm2.o.h"

#include <Halide.h>
#include <tiramisu/tiramisu.h>
#include <tiramisu/utils.h>

#include <iostream>
#include "benchmarks.h"
#include <math.h>

#define M_DIM M
#define N_DIM N

int nrm2_ref(int n, double * X, double *nrm)
{
    double sum = 0;

    for (int i = 0; i < n; ++i)
    	 sum += X[i] * X[i];

    nrm[0] = sqrt(sum);
    return 0;
}

int main(int argc, char** argv)
{
    std::vector<std::chrono::duration<double, std::milli>> duration_vector_1, duration_vector_2;

    bool run_ref = false, run_tiramisu = false;

    const char* env_ref = std::getenv("RUN_REF");
    if (env_ref != NULL && env_ref[0] == '1')
        run_ref = true;

    const char* env_tiramisu = std::getenv("RUN_TIRAMISU");
    if (env_tiramisu != NULL && env_tiramisu[0] == '1')
        run_tiramisu = true;

    // ---------------------------------------------------------------------
    // ---------------------------------------------------------------------
    // ---------------------------------------------------------------------

    Halide::Buffer<double> b_result(1), b_result_ref(1);

    Halide::Buffer<double> b_X(N_DIM);
    init_buffer(b_X, (double) 1);

    /**
       X vector is initialized to 1
    **/

    {
        for (int i = 0; i < NB_TESTS; ++i)
        {
            auto start = std::chrono::high_resolution_clock::now();

            if (run_ref)
	    	nrm2_ref(N_DIM, b_X.data(), b_result_ref.data() );

            auto end = std::chrono::high_resolution_clock::now();
            duration_vector_1.push_back(end - start);
        }
    }

    {
        for (int i = 0; i < NB_TESTS; ++i)
        {
            auto start = std::chrono::high_resolution_clock::now();

            if (run_tiramisu)
	    	nrm2(b_X.raw_buffer(), b_result.raw_buffer());

            auto end = std::chrono::high_resolution_clock::now();
            duration_vector_2.push_back(end - start);
        }
    }

    print_time("performance_cpu.csv", "nrm2",
	       {"Ref", "Tiramisu"},
	       {median(duration_vector_1), median(duration_vector_2)});

    if (CHECK_CORRECTNESS && run_ref && run_tiramisu)
        compare_buffers("nrm2", b_result, b_result_ref);

    if (PRINT_OUTPUT)
    {
        std::cout << "Tiramisu " << std::endl;
        print_buffer(b_result);

        std::cout << "Reference " << std::endl;
        print_buffer(b_result_ref);
    }

    return 0;
}
<commit_msg>Fix code style<commit_after>#include "generated_nrm2.o.h"

#include <Halide.h>
#include <tiramisu/tiramisu.h>
#include <tiramisu/utils.h>

#include <iostream>
#include "benchmarks.h"
#include <math.h>

#define M_DIM M
#define N_DIM N

int nrm2_ref(int n, double * X, double * nrm)
{
    double sum = 0;

    for (int i = 0; i < n; ++i)
    	 sum += X[i] * X[i];

    nrm[0] = sqrt(sum);
    return 0;
}

int main(int argc, char** argv)
{
    std::vector<std::chrono::duration<double, std::milli>> duration_vector_1, duration_vector_2;

    bool run_ref = false, run_tiramisu = false;

    const char* env_ref = std::getenv("RUN_REF");
    if (env_ref != NULL && env_ref[0] == '1')
        run_ref = true;

    const char* env_tiramisu = std::getenv("RUN_TIRAMISU");
    if (env_tiramisu != NULL && env_tiramisu[0] == '1')
        run_tiramisu = true;

    // ---------------------------------------------------------------------
    // ---------------------------------------------------------------------
    // ---------------------------------------------------------------------

    Halide::Buffer<double> b_result(1), b_result_ref(1);

    Halide::Buffer<double> b_X(N_DIM);
    init_buffer(b_X, (double) 1);

    /**
       X vector is initialized to 1
    **/

    {
        for (int i = 0; i < NB_TESTS; ++i)
        {
            auto start = std::chrono::high_resolution_clock::now();

            if (run_ref)
    	    	nrm2_ref(N_DIM, b_X.data(), b_result_ref.data());

            auto end = std::chrono::high_resolution_clock::now();
            duration_vector_1.push_back(end - start);
        }
    }

    {
        for (int i = 0; i < NB_TESTS; ++i)
        {
            auto start = std::chrono::high_resolution_clock::now();

            if (run_tiramisu)
	        	nrm2(b_X.raw_buffer(), b_result.raw_buffer());

            auto end = std::chrono::high_resolution_clock::now();
            duration_vector_2.push_back(end - start);
        }
    }

    print_time("performance_cpu.csv", "nrm2",
	       {"Ref", "Tiramisu"},
	       {median(duration_vector_1), median(duration_vector_2)});

    if (CHECK_CORRECTNESS && run_ref && run_tiramisu)
        compare_buffers("nrm2", b_result, b_result_ref);

    if (PRINT_OUTPUT)
    {
        std::cout << "Tiramisu " << std::endl;
        print_buffer(b_result);

        std::cout << "Reference " << std::endl;
        print_buffer(b_result_ref);
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "PrimeTower.h"

#include <limits>

#include "ExtruderTrain.h"
#include "sliceDataStorage.h"
#include "gcodeExport.h"
#include "LayerPlan.h"
#include "infill.h"
#include "PrintFeature.h"

namespace cura
{

PrimeTower::PrimeTower(const SliceDataStorage& storage)
: is_hollow(false)
, wipe_from_middle(false)
{
    enabled = storage.getSettingBoolean("prime_tower_enable")
           && storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
           && storage.getSettingInMicrons("prime_tower_size") > 10;
    if (enabled)
    {
        generateGroundpoly(storage);
    }
}

void PrimeTower::generateGroundpoly(const SliceDataStorage& storage)
{
    extruder_count = storage.meshgroup->getExtruderCount();

    int64_t prime_tower_wall_thickness = storage.getSettingInMicrons("prime_tower_wall_thickness");
    int64_t tower_size = storage.getSettingInMicrons("prime_tower_size");

    if (prime_tower_wall_thickness * 2 < tower_size)
    {
        is_hollow = true;
    }

    PolygonRef p = ground_poly.newPoly();
    int tower_distance = 0;
    int x = storage.getSettingInMicrons("prime_tower_position_x"); // storage.model_max.x
    int y = storage.getSettingInMicrons("prime_tower_position_y"); // storage.model_max.y
    p.add(Point(x + tower_distance, y + tower_distance));
    p.add(Point(x + tower_distance, y + tower_distance + tower_size));
    p.add(Point(x + tower_distance - tower_size, y + tower_distance + tower_size));
    p.add(Point(x + tower_distance - tower_size, y + tower_distance));
    middle = Point(x - tower_size / 2, y + tower_size / 2);

    if (is_hollow)
    {
        ground_poly = ground_poly.difference(ground_poly.offset(-prime_tower_wall_thickness));
    }

    post_wipe_point = Point(x + tower_distance - tower_size / 2, y + tower_distance + tower_size / 2);
}

void PrimeTower::generatePaths(const SliceDataStorage& storage)
{
    enabled &= storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches.
    if (enabled)
    {
        generatePaths_denseInfill(storage);
        generateWipeLocations(storage);
    }
}

void PrimeTower::generatePaths_denseInfill(const SliceDataStorage& storage)
{
    int n_patterns = 2; // alternating patterns between layers
    int infill_overlap = 60; // so that it can't be zero; EDIT: wtf?
    int extra_infill_shift = 0;

    int64_t z = 0; // (TODO) because the prime tower stores the paths for each extruder for once instead of generating each layer, we don't know the z position

    for (int extruder = 0; extruder < extruder_count; extruder++)
    {
        int line_width = storage.meshgroup->getExtruderTrain(extruder)->getSettingInMicrons("prime_tower_line_width");
        patterns_per_extruder.emplace_back(n_patterns);
        std::vector<ExtrusionMoves>& patterns = patterns_per_extruder.back();
        patterns.resize(n_patterns);
        for (int pattern_idx = 0; pattern_idx < n_patterns; pattern_idx++)
        {
            patterns[pattern_idx].polygons = ground_poly.offset(-line_width / 2);
            Polygons& result_lines = patterns[pattern_idx].lines;
            int outline_offset = -line_width;
            int line_distance = line_width;
            double fill_angle = 45 + pattern_idx * 90;
            Polygons result_polygons; // should remain empty, since we generate lines pattern!
            Infill infill_comp(EFillMethod::LINES, ground_poly, outline_offset, line_width, line_distance, infill_overlap, fill_angle, z, extra_infill_shift);
            infill_comp.generate(result_polygons, result_lines);
        }
    }
}

void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder) const
{
    if (!enabled)
    {
        return;
    }
    if (gcodeLayer.getPrimeTowerIsPlanned())
    { // don't print the prime tower if it has been printed already
        return;
    }

    if (layer_nr > storage.max_print_height_second_to_last_extruder + 1)
    {
        return;
    }

    bool pre_wipe = storage.meshgroup->getExtruderTrain(new_extruder)->getSettingBoolean("dual_pre_wipe");
    bool post_wipe = storage.meshgroup->getExtruderTrain(prev_extruder)->getSettingBoolean("prime_tower_wipe_enabled");

    if (prev_extruder == new_extruder)
    {
        pre_wipe = false;
        post_wipe = false;
    }
    // pre-wipe:
    if (pre_wipe)
    {
        preWipe(storage, gcodeLayer, layer_nr, new_extruder);
    }

    addToGcode_denseInfill(gcodeLayer, layer_nr, new_extruder);

    // post-wipe:
    if (post_wipe)
    { //Make sure we wipe the old extruder on the prime tower.
        gcodeLayer.addTravel(post_wipe_point - gcode.getExtruderOffset(prev_extruder) + gcode.getExtruderOffset(new_extruder));
    }

    gcodeLayer.setPrimeTowerIsPlanned();
}

void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const int layer_nr, const int extruder_nr) const
{
    const ExtrusionMoves& pattern = patterns_per_extruder[extruder_nr][((layer_nr % 2) + 2) % 2]; // +2) %2 to handle negative layer numbers

    const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr];

    gcode_layer.addPolygonsByOptimizer(pattern.polygons, &config);
    gcode_layer.addLinesByOptimizer(pattern.lines, &config, SpaceFillType::Lines);
}

Point PrimeTower::getLocationBeforePrimeTower(const SliceDataStorage& storage) const
{
    Point ret(0, 0);
    int absolute_starting_points = 0;
    for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); extruder_nr++)
    {
        ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(0);
        if (train.getSettingBoolean("machine_extruder_start_pos_abs"))
        {
            ret += Point(train.getSettingInMicrons("machine_extruder_start_pos_x"), train.getSettingInMicrons("machine_extruder_start_pos_y"));
            absolute_starting_points++;
        }
    }
    if (absolute_starting_points > 0)
    { // take the average over all absolute starting positions
        ret /= absolute_starting_points;
    }
    else
    { // use the middle of the bed
        if (!storage.getSettingBoolean("machine_center_is_zero"))
        {
            ret = Point(storage.getSettingInMicrons("machine_width"), storage.getSettingInMicrons("machine_depth")) / 2;
        }
        // otherwise keep (0, 0)
    }
    return ret;
}

void PrimeTower::generateWipeLocations(const SliceDataStorage& storage)
{
    wipe_from_middle = is_hollow;
    // only wipe from the middle of the prime tower if we have a z hop already on the first move after the layer switch
    for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); extruder_nr++)
    {
        const ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(extruder_nr);
        wipe_from_middle &= train.getSettingBoolean("retraction_hop_enabled")
                        && (!train.getSettingBoolean("retraction_hop_only_when_collides") || train.getSettingBoolean("retraction_hop_after_extruder_switch"));
    }

    PolygonsPointIndex segment_start; // from where to start the sequence of wipe points
    PolygonsPointIndex segment_end; // where to end the sequence of wipe points

    if (wipe_from_middle)
    {
        // take the same start as end point so that the whole poly os covered.
        // find the inner polygon.
        segment_start = segment_end = PolygonUtils::findNearestVert(middle, ground_poly);
    }
    else
    {
        // take the closer corner of the wipe tower and generate wipe locations on that side only:
        //
        //     |
        //     |
        //     +-----
        //  .
        //  ^ nozzle switch location
        Point from = getLocationBeforePrimeTower(storage);

        // find the single line segment closest to [from] pointing most toward [from]
        PolygonsPointIndex closest_vert = PolygonUtils::findNearestVert(from, ground_poly);
        PolygonsPointIndex prev = closest_vert.prev();
        PolygonsPointIndex next = closest_vert.next();
        int64_t prev_dot_score = dot(from - closest_vert.p(), turn90CCW(prev.p() - closest_vert.p()));
        int64_t next_dot_score = dot(from - closest_vert.p(), turn90CCW(closest_vert.p() - next.p()));
        if (prev_dot_score > next_dot_score)
        {
            segment_start = prev;
            segment_end = closest_vert;
        }
        else
        {
            segment_start = closest_vert;
            segment_end = next;
        }
    }

    PolygonUtils::spreadDots(segment_start, segment_end, number_of_pre_wipe_locations, pre_wipe_locations);
}

void PrimeTower::preWipe(const SliceDataStorage& storage, LayerPlan& gcode_layer, const int layer_nr, const int extruder_nr) const
{
    int current_pre_wipe_location_idx = (pre_wipe_location_skip * layer_nr) % number_of_pre_wipe_locations;
    const ClosestPolygonPoint wipe_location = pre_wipe_locations[current_pre_wipe_location_idx];

    ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(extruder_nr);
    const int inward_dist = train.getSettingInMicrons("machine_nozzle_size") * 3 / 2 ;
    const int start_dist = train.getSettingInMicrons("machine_nozzle_size") * 2;
    const Point end = PolygonUtils::moveInsideDiagonally(wipe_location, inward_dist);
    const Point outward_dir = wipe_location.location - end;
    const Point start = wipe_location.location + normal(outward_dir, start_dist);

    if (wipe_from_middle)
    {
        // for hollow wipe tower:
        // start from above
        // go to wipe start
        // go to the Z height of the previous/current layer
        // wipe
        // go to normal layer height (automatically on the next extrusion move)...
        GCodePath& toward_middle = gcode_layer.addTravel(middle);
        toward_middle.perform_z_hop = true;
        gcode_layer.forceNewPathStart();
        GCodePath& toward_wipe_start = gcode_layer.addTravel_simple(start);
        toward_wipe_start.perform_z_hop = false;
        toward_wipe_start.retract = true;
    }
    else
    {
        gcode_layer.addTravel(start);
    }

    float flow = 0.0001; // Force this path being interpreted as an extrusion path, so that no Z hop will occur (TODO: really separately handle travel and extrusion moves)

    // Check if we need to purge before wiping on the prime tower.
    if(train.getSettingBoolean("prime_tower_purge_enabled"))
    {
        // We can't do a "real" stand still & extrude move, we need to fake one.
        // We do this by changing the flow of the "move to end of wipe" position.
        const unsigned int infill_line_width = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr].getLineWidth();
        const double layer_height_mm = (layer_nr == 0)? train.getSettingInMillimeters("layer_height_0") : train.getSettingInMillimeters("layer_height");
        const double normal_volume = INT2MM(INT2MM(start_dist * infill_line_width)) * layer_height_mm; // Volume extruded on the "normal" move
        const double total_volume = train.getSettingBoolean("prime_tower_purge_volume"); // Volume to be primed
        flow = total_volume / normal_volume; // New flow ratio
    }

    gcode_layer.addExtrusionMove(end, &gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr], SpaceFillType::None, flow);
}

void PrimeTower::subtractFromSupport(SliceDataStorage& storage)
{
    const Polygons outside_polygon = ground_poly.getOutsidePolygons();
    for(size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++)
    {
        storage.support.supportLayers[layer].supportAreas = storage.support.supportLayers[layer].supportAreas.difference(outside_polygon);
    }
}

}//namespace cura
<commit_msg>Purging now always happens before we do a wipe<commit_after>#include "PrimeTower.h"

#include <limits>

#include "ExtruderTrain.h"
#include "sliceDataStorage.h"
#include "gcodeExport.h"
#include "LayerPlan.h"
#include "infill.h"
#include "PrintFeature.h"

namespace cura
{

PrimeTower::PrimeTower(const SliceDataStorage& storage)
: is_hollow(false)
, wipe_from_middle(false)
{
    enabled = storage.getSettingBoolean("prime_tower_enable")
           && storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
           && storage.getSettingInMicrons("prime_tower_size") > 10;
    if (enabled)
    {
        generateGroundpoly(storage);
    }
}

void PrimeTower::generateGroundpoly(const SliceDataStorage& storage)
{
    extruder_count = storage.meshgroup->getExtruderCount();

    int64_t prime_tower_wall_thickness = storage.getSettingInMicrons("prime_tower_wall_thickness");
    int64_t tower_size = storage.getSettingInMicrons("prime_tower_size");

    if (prime_tower_wall_thickness * 2 < tower_size)
    {
        is_hollow = true;
    }

    PolygonRef p = ground_poly.newPoly();
    int tower_distance = 0;
    int x = storage.getSettingInMicrons("prime_tower_position_x"); // storage.model_max.x
    int y = storage.getSettingInMicrons("prime_tower_position_y"); // storage.model_max.y
    p.add(Point(x + tower_distance, y + tower_distance));
    p.add(Point(x + tower_distance, y + tower_distance + tower_size));
    p.add(Point(x + tower_distance - tower_size, y + tower_distance + tower_size));
    p.add(Point(x + tower_distance - tower_size, y + tower_distance));
    middle = Point(x - tower_size / 2, y + tower_size / 2);

    if (is_hollow)
    {
        ground_poly = ground_poly.difference(ground_poly.offset(-prime_tower_wall_thickness));
    }

    post_wipe_point = Point(x + tower_distance - tower_size / 2, y + tower_distance + tower_size / 2);
}

void PrimeTower::generatePaths(const SliceDataStorage& storage)
{
    enabled &= storage.max_print_height_second_to_last_extruder >= 0; //Maybe it turns out that we don't need a prime tower after all because there are no layer switches.
    if (enabled)
    {
        generatePaths_denseInfill(storage);
        generateWipeLocations(storage);
    }
}

void PrimeTower::generatePaths_denseInfill(const SliceDataStorage& storage)
{
    int n_patterns = 2; // alternating patterns between layers
    int infill_overlap = 60; // so that it can't be zero; EDIT: wtf?
    int extra_infill_shift = 0;

    int64_t z = 0; // (TODO) because the prime tower stores the paths for each extruder for once instead of generating each layer, we don't know the z position

    for (int extruder = 0; extruder < extruder_count; extruder++)
    {
        int line_width = storage.meshgroup->getExtruderTrain(extruder)->getSettingInMicrons("prime_tower_line_width");
        patterns_per_extruder.emplace_back(n_patterns);
        std::vector<ExtrusionMoves>& patterns = patterns_per_extruder.back();
        patterns.resize(n_patterns);
        for (int pattern_idx = 0; pattern_idx < n_patterns; pattern_idx++)
        {
            patterns[pattern_idx].polygons = ground_poly.offset(-line_width / 2);
            Polygons& result_lines = patterns[pattern_idx].lines;
            int outline_offset = -line_width;
            int line_distance = line_width;
            double fill_angle = 45 + pattern_idx * 90;
            Polygons result_polygons; // should remain empty, since we generate lines pattern!
            Infill infill_comp(EFillMethod::LINES, ground_poly, outline_offset, line_width, line_distance, infill_overlap, fill_angle, z, extra_infill_shift);
            infill_comp.generate(result_polygons, result_lines);
        }
    }
}

void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder) const
{
    if (!enabled)
    {
        return;
    }
    if (gcodeLayer.getPrimeTowerIsPlanned())
    { // don't print the prime tower if it has been printed already
        return;
    }

    if (layer_nr > storage.max_print_height_second_to_last_extruder + 1)
    {
        return;
    }

    bool pre_wipe = storage.meshgroup->getExtruderTrain(new_extruder)->getSettingBoolean("dual_pre_wipe");
    bool post_wipe = storage.meshgroup->getExtruderTrain(prev_extruder)->getSettingBoolean("prime_tower_wipe_enabled");

    if (prev_extruder == new_extruder)
    {
        pre_wipe = false;
        post_wipe = false;
    }
    // pre-wipe:
    if (pre_wipe)
    {
        preWipe(storage, gcodeLayer, layer_nr, new_extruder);
    }

    addToGcode_denseInfill(gcodeLayer, layer_nr, new_extruder);

    // post-wipe:
    if (post_wipe)
    { //Make sure we wipe the old extruder on the prime tower.
        gcodeLayer.addTravel(post_wipe_point - gcode.getExtruderOffset(prev_extruder) + gcode.getExtruderOffset(new_extruder));
    }

    gcodeLayer.setPrimeTowerIsPlanned();
}

void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const int layer_nr, const int extruder_nr) const
{
    const ExtrusionMoves& pattern = patterns_per_extruder[extruder_nr][((layer_nr % 2) + 2) % 2]; // +2) %2 to handle negative layer numbers

    const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr];

    gcode_layer.addPolygonsByOptimizer(pattern.polygons, &config);
    gcode_layer.addLinesByOptimizer(pattern.lines, &config, SpaceFillType::Lines);
}

Point PrimeTower::getLocationBeforePrimeTower(const SliceDataStorage& storage) const
{
    Point ret(0, 0);
    int absolute_starting_points = 0;
    for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); extruder_nr++)
    {
        ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(0);
        if (train.getSettingBoolean("machine_extruder_start_pos_abs"))
        {
            ret += Point(train.getSettingInMicrons("machine_extruder_start_pos_x"), train.getSettingInMicrons("machine_extruder_start_pos_y"));
            absolute_starting_points++;
        }
    }
    if (absolute_starting_points > 0)
    { // take the average over all absolute starting positions
        ret /= absolute_starting_points;
    }
    else
    { // use the middle of the bed
        if (!storage.getSettingBoolean("machine_center_is_zero"))
        {
            ret = Point(storage.getSettingInMicrons("machine_width"), storage.getSettingInMicrons("machine_depth")) / 2;
        }
        // otherwise keep (0, 0)
    }
    return ret;
}

void PrimeTower::generateWipeLocations(const SliceDataStorage& storage)
{
    wipe_from_middle = is_hollow;
    // only wipe from the middle of the prime tower if we have a z hop already on the first move after the layer switch
    for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); extruder_nr++)
    {
        const ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(extruder_nr);
        wipe_from_middle &= train.getSettingBoolean("retraction_hop_enabled")
                        && (!train.getSettingBoolean("retraction_hop_only_when_collides") || train.getSettingBoolean("retraction_hop_after_extruder_switch"));
    }

    PolygonsPointIndex segment_start; // from where to start the sequence of wipe points
    PolygonsPointIndex segment_end; // where to end the sequence of wipe points

    if (wipe_from_middle)
    {
        // take the same start as end point so that the whole poly os covered.
        // find the inner polygon.
        segment_start = segment_end = PolygonUtils::findNearestVert(middle, ground_poly);
    }
    else
    {
        // take the closer corner of the wipe tower and generate wipe locations on that side only:
        //
        //     |
        //     |
        //     +-----
        //  .
        //  ^ nozzle switch location
        Point from = getLocationBeforePrimeTower(storage);

        // find the single line segment closest to [from] pointing most toward [from]
        PolygonsPointIndex closest_vert = PolygonUtils::findNearestVert(from, ground_poly);
        PolygonsPointIndex prev = closest_vert.prev();
        PolygonsPointIndex next = closest_vert.next();
        int64_t prev_dot_score = dot(from - closest_vert.p(), turn90CCW(prev.p() - closest_vert.p()));
        int64_t next_dot_score = dot(from - closest_vert.p(), turn90CCW(closest_vert.p() - next.p()));
        if (prev_dot_score > next_dot_score)
        {
            segment_start = prev;
            segment_end = closest_vert;
        }
        else
        {
            segment_start = closest_vert;
            segment_end = next;
        }
    }

    PolygonUtils::spreadDots(segment_start, segment_end, number_of_pre_wipe_locations, pre_wipe_locations);
}

void PrimeTower::preWipe(const SliceDataStorage& storage, LayerPlan& gcode_layer, const int layer_nr, const int extruder_nr) const
{
    int current_pre_wipe_location_idx = (pre_wipe_location_skip * layer_nr) % number_of_pre_wipe_locations;
    const ClosestPolygonPoint wipe_location = pre_wipe_locations[current_pre_wipe_location_idx];

    ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(extruder_nr);
    const int inward_dist = train.getSettingInMicrons("machine_nozzle_size") * 3 / 2 ;
    const int start_dist = train.getSettingInMicrons("machine_nozzle_size") * 2;
    const Point prime_end = PolygonUtils::moveInsideDiagonally(wipe_location, inward_dist);
    const Point outward_dir = wipe_location.location - prime_end;
    const Point prime_start = wipe_location.location + normal(outward_dir, start_dist);

    const double purge_volume = train.getSettingInCubicMillimeters("prime_tower_purge_volume"); // Volume to be primed
    if (wipe_from_middle)
    {
        // for hollow wipe tower:
        // start from above
        // go to wipe start
        // go to the Z height of the previous/current layer
        // wipe
        // go to normal layer height (automatically on the next extrusion move)...
        GCodePath& toward_middle = gcode_layer.addTravel(middle);
        toward_middle.perform_z_hop = true;
        gcode_layer.forceNewPathStart();

        if(purge_volume > 0)
        {
            // Find out how much purging needs to be done.
            int purge_move_length = vSize(middle - prime_start);
            const unsigned int line_width = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr].getLineWidth();
            const double layer_height_mm = (layer_nr == 0)? train.getSettingInMillimeters("layer_height_0") : train.getSettingInMillimeters("layer_height");
            const double normal_volume = INT2MM(INT2MM(purge_move_length * line_width)) * layer_height_mm; // Volume extruded on the "normal" move
            float purge_flow = purge_volume / normal_volume;

            // As we need a plan, which can't have a stationary extrusion, we use an extrusion move to prime.
            // This has the added benefit that it will evenly spread the primed material inside the tower.
            gcode_layer.addExtrusionMove(prime_start, &gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr], SpaceFillType::None, purge_flow);
        } else
        {
            // Normal move behavior to wipe start location.
            GCodePath& toward_wipe_start = gcode_layer.addTravel_simple(prime_start);
            toward_wipe_start.perform_z_hop = false;
            toward_wipe_start.retract = true;
        }
    }
    else
    {
        if(purge_volume > 0)
        {
            // Find location to start purge (we're purging right outside of the tower)
            const Point purge_start = prime_start + normal(outward_dir, start_dist);
            gcode_layer.addTravel(purge_start);

            // Calculate how much we need to purge
            int purge_move_length = vSize(purge_start - prime_start);
            const unsigned int line_width = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr].getLineWidth();
            const double layer_height_mm = (layer_nr == 0)? train.getSettingInMillimeters("layer_height_0") : train.getSettingInMillimeters("layer_height");
            const double normal_volume = INT2MM(INT2MM(purge_move_length * line_width)) * layer_height_mm; // Volume extruded on the "normal" move
            float purge_flow = purge_volume / normal_volume;

            // As we need a plan, which can't have a stationary extrusion, we use an extrusion move to prime.
            gcode_layer.addExtrusionMove(prime_start, &gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr], SpaceFillType::None, purge_flow);

        }
        gcode_layer.addTravel(prime_start);
    }

    float flow = 0.0001; // Force this path being interpreted as an extrusion path, so that no Z hop will occur (TODO: really separately handle travel and extrusion moves)
    gcode_layer.addExtrusionMove(prime_end, &gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr], SpaceFillType::None, flow);
}

void PrimeTower::subtractFromSupport(SliceDataStorage& storage)
{
    const Polygons outside_polygon = ground_poly.getOutsidePolygons();
    for(size_t layer = 0; layer <= (size_t)storage.max_print_height_second_to_last_extruder + 1 && layer < storage.support.supportLayers.size(); layer++)
    {
        storage.support.supportLayers[layer].supportAreas = storage.support.supportLayers[layer].supportAreas.difference(outside_polygon);
    }
}

}//namespace cura
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageViewer2.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImageViewer2.h"
#include "vtkObjectFactory.h"
#include "vtkInteractorStyleImage.h"
#include "vtkCommand.h"

vtkCxxRevisionMacro(vtkImageViewer2, "1.8");
vtkStandardNewMacro(vtkImageViewer2);

//----------------------------------------------------------------------------
vtkImageViewer2::vtkImageViewer2()
{
  this->RenderWindow = vtkRenderWindow::New();
  this->Renderer     = vtkRenderer::New();
  this->ImageActor   = vtkImageActor::New();
  this->WindowLevel  = vtkImageMapToWindowLevelColors::New();

  // setup the pipeline
  this->ImageActor->SetInput(this->WindowLevel->GetOutput());
  this->Renderer->AddProp(this->ImageActor);
  this->RenderWindow->AddRenderer(this->Renderer);
  this->FirstRender = 1;

  this->Interactor = 0;
  this->InteractorStyle = 0;
}

//----------------------------------------------------------------------------
vtkImageViewer2::~vtkImageViewer2()
{
  this->WindowLevel->Delete();
  this->ImageActor->Delete();
  this->Renderer->Delete();
  this->RenderWindow->Delete();

  if (this->Interactor)
    {
    this->Interactor->Delete();
    }
  if (this->InteractorStyle)
    {
    this->InteractorStyle->Delete();
    }
}

//----------------------------------------------------------------------------
void vtkImageViewer2::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << *this->RenderWindow << endl;
  os << indent << *this->Renderer << endl;
  os << indent << *this->ImageActor << endl;
  os << indent << *this->WindowLevel << endl;
}

//----------------------------------------------------------------------------
void vtkImageViewer2::SetSize(int a[2])
{
  this->SetSize(a[0],a[1]);
}
//----------------------------------------------------------------------------
void vtkImageViewer2::SetPosition(int a[2])
{
  this->SetPosition(a[0],a[1]);
}

class vtkImageViewer2Callback : public vtkCommand
{
public:
  static vtkImageViewer2Callback *New() {
    return new vtkImageViewer2Callback; }

  void Execute(vtkObject *caller, unsigned long vtkNotUsed(event),
               void *callData)
    {
      if (callData)
        {
        this->InitialWindow = this->IV->GetWindowLevel()->GetWindow();
        this->InitialLevel = this->IV->GetWindowLevel()->GetLevel();
        return;
        }

      // adjust the window level here
      vtkInteractorStyleImage *isi =
        static_cast<vtkInteractorStyleImage *>(caller);

      int *size = this->IV->GetRenderWindow()->GetSize();
      float window = this->InitialWindow;
      float level = this->InitialLevel;

      // compute normalized delta
      float dx = 4.0 * (isi->GetWindowLevelCurrentPosition()[0] -
                        isi->GetWindowLevelStartPosition()[0]) / size[0];
      float dy = 4.0 * (isi->GetWindowLevelStartPosition()[1] -
                        isi->GetWindowLevelCurrentPosition()[1]) / size[1];

      // scale by current values
      if (fabs(window) > 0.01)
        {
        dx = dx * window;
        }
      else
        {
        dx = dx * (window < 0 ? -0.01 : 0.01);
        }
      if (fabs(level) > 0.01)
        {
        dy = dy * level;
        }
      else
        {
        dy = dy * (level < 0 ? -0.01 : 0.01);
        }

      // abs so that direction does not flip
      if (window < 0.0)
        {
        dx = -1*dx;
        }
      if (level < 0.0)
        {
        dy = -1*dy;
        }

      // compute new window level
      float newWindow = dx + window;
      float newLevel;
      newLevel = level - dy;

      // stay away from zero and really
      if (fabs(newWindow) < 0.01)
        {
        newWindow = 0.01*(newWindow < 0 ? -1 : 1);
        }
      if (fabs(newLevel) < 0.01)
        {
        newLevel = 0.01*(newLevel < 0 ? -1 : 1);
        }

      this->IV->GetWindowLevel()->SetWindow(newWindow);
      this->IV->GetWindowLevel()->SetLevel(newLevel);
      this->IV->Render();
    }

  vtkImageViewer2 *IV;
  float InitialWindow;
  float InitialLevel;
};

void vtkImageViewer2::SetupInteractor(vtkRenderWindowInteractor *rwi)
{
  if (this->Interactor && rwi != this->Interactor)
    {
    this->Interactor->Delete();
    }
  if (!this->InteractorStyle)
    {
    this->InteractorStyle = vtkInteractorStyleImage::New();
    vtkImageViewer2Callback *cbk = vtkImageViewer2Callback::New();
    cbk->IV = this;
    this->InteractorStyle->AddObserver(vtkCommand::WindowLevelEvent,cbk);
    cbk->Delete();
    }

  if (!this->Interactor)
    {
    this->Interactor = rwi;
    rwi->Register(this);
    }
  this->Interactor->SetInteractorStyle(this->InteractorStyle);
  this->Interactor->SetRenderWindow(this->RenderWindow);
}

void vtkImageViewer2::Render()
{
  if (this->FirstRender)
    {
    // initialize the size if not set yet
    if (this->RenderWindow->GetSize()[0] == 0 && this->ImageActor->GetInput())
      {
      // get the size from the mappers input
      this->WindowLevel->GetInput()->UpdateInformation();
      int *ext = this->WindowLevel->GetInput()->GetWholeExtent();
      // if it would be smaller than 100 by 100 then limit to 100 by 100
      int xs = ext[1] - ext[0] + 1;
      int ys = ext[3] - ext[2] + 1;
      this->RenderWindow->SetSize(xs < 150 ? 150 : xs,
                                  ys < 100 ? 100 : ys);
      this->Renderer->GetActiveCamera()->SetParallelScale(xs < 150 ? 75 : xs/2);
      }
    this->Renderer->GetActiveCamera()->ParallelProjectionOn();
    this->FirstRender = 0;
    }

  this->RenderWindow->Render();
}

<commit_msg>minor change to parallel scaling<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageViewer2.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkImageViewer2.h"
#include "vtkObjectFactory.h"
#include "vtkInteractorStyleImage.h"
#include "vtkCommand.h"

vtkCxxRevisionMacro(vtkImageViewer2, "1.9");
vtkStandardNewMacro(vtkImageViewer2);

//----------------------------------------------------------------------------
vtkImageViewer2::vtkImageViewer2()
{
  this->RenderWindow = vtkRenderWindow::New();
  this->Renderer     = vtkRenderer::New();
  this->ImageActor   = vtkImageActor::New();
  this->WindowLevel  = vtkImageMapToWindowLevelColors::New();

  // setup the pipeline
  this->ImageActor->SetInput(this->WindowLevel->GetOutput());
  this->Renderer->AddProp(this->ImageActor);
  this->RenderWindow->AddRenderer(this->Renderer);
  this->FirstRender = 1;

  this->Interactor = 0;
  this->InteractorStyle = 0;
}

//----------------------------------------------------------------------------
vtkImageViewer2::~vtkImageViewer2()
{
  this->WindowLevel->Delete();
  this->ImageActor->Delete();
  this->Renderer->Delete();
  this->RenderWindow->Delete();

  if (this->Interactor)
    {
    this->Interactor->Delete();
    }
  if (this->InteractorStyle)
    {
    this->InteractorStyle->Delete();
    }
}

//----------------------------------------------------------------------------
void vtkImageViewer2::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << *this->RenderWindow << endl;
  os << indent << *this->Renderer << endl;
  os << indent << *this->ImageActor << endl;
  os << indent << *this->WindowLevel << endl;
}

//----------------------------------------------------------------------------
void vtkImageViewer2::SetSize(int a[2])
{
  this->SetSize(a[0],a[1]);
}
//----------------------------------------------------------------------------
void vtkImageViewer2::SetPosition(int a[2])
{
  this->SetPosition(a[0],a[1]);
}

class vtkImageViewer2Callback : public vtkCommand
{
public:
  static vtkImageViewer2Callback *New() {
    return new vtkImageViewer2Callback; }

  void Execute(vtkObject *caller, unsigned long vtkNotUsed(event),
               void *callData)
    {
      if (callData)
        {
        this->InitialWindow = this->IV->GetWindowLevel()->GetWindow();
        this->InitialLevel = this->IV->GetWindowLevel()->GetLevel();
        return;
        }

      // adjust the window level here
      vtkInteractorStyleImage *isi =
        static_cast<vtkInteractorStyleImage *>(caller);

      int *size = this->IV->GetRenderWindow()->GetSize();
      float window = this->InitialWindow;
      float level = this->InitialLevel;

      // compute normalized delta
      float dx = 4.0 * (isi->GetWindowLevelCurrentPosition()[0] -
                        isi->GetWindowLevelStartPosition()[0]) / size[0];
      float dy = 4.0 * (isi->GetWindowLevelStartPosition()[1] -
                        isi->GetWindowLevelCurrentPosition()[1]) / size[1];

      // scale by current values
      if (fabs(window) > 0.01)
        {
        dx = dx * window;
        }
      else
        {
        dx = dx * (window < 0 ? -0.01 : 0.01);
        }
      if (fabs(level) > 0.01)
        {
        dy = dy * level;
        }
      else
        {
        dy = dy * (level < 0 ? -0.01 : 0.01);
        }

      // abs so that direction does not flip
      if (window < 0.0)
        {
        dx = -1*dx;
        }
      if (level < 0.0)
        {
        dy = -1*dy;
        }

      // compute new window level
      float newWindow = dx + window;
      float newLevel;
      newLevel = level - dy;

      // stay away from zero and really
      if (fabs(newWindow) < 0.01)
        {
        newWindow = 0.01*(newWindow < 0 ? -1 : 1);
        }
      if (fabs(newLevel) < 0.01)
        {
        newLevel = 0.01*(newLevel < 0 ? -1 : 1);
        }

      this->IV->GetWindowLevel()->SetWindow(newWindow);
      this->IV->GetWindowLevel()->SetLevel(newLevel);
      this->IV->Render();
    }

  vtkImageViewer2 *IV;
  float InitialWindow;
  float InitialLevel;
};

void vtkImageViewer2::SetupInteractor(vtkRenderWindowInteractor *rwi)
{
  if (this->Interactor && rwi != this->Interactor)
    {
    this->Interactor->Delete();
    }
  if (!this->InteractorStyle)
    {
    this->InteractorStyle = vtkInteractorStyleImage::New();
    vtkImageViewer2Callback *cbk = vtkImageViewer2Callback::New();
    cbk->IV = this;
    this->InteractorStyle->AddObserver(vtkCommand::WindowLevelEvent,cbk);
    cbk->Delete();
    }

  if (!this->Interactor)
    {
    this->Interactor = rwi;
    rwi->Register(this);
    }
  this->Interactor->SetInteractorStyle(this->InteractorStyle);
  this->Interactor->SetRenderWindow(this->RenderWindow);
}

void vtkImageViewer2::Render()
{
  if (this->FirstRender)
    {
    // initialize the size if not set yet
    if (this->RenderWindow->GetSize()[0] == 0 && this->ImageActor->GetInput())
      {
      // get the size from the mappers input
      this->WindowLevel->GetInput()->UpdateInformation();
      int *ext = this->WindowLevel->GetInput()->GetWholeExtent();
      // if it would be smaller than 100 by 100 then limit to 100 by 100
      int xs = ext[1] - ext[0] + 1;
      int ys = ext[3] - ext[2] + 1;
      this->RenderWindow->SetSize(xs < 150 ? 150 : xs,
                                  ys < 100 ? 100 : ys);
      this->Renderer->GetActiveCamera()->SetParallelScale(xs < 150 ? 75 : (xs-1)/2.0);
      }
    this->Renderer->GetActiveCamera()->ParallelProjectionOn();
    this->FirstRender = 0;
    }

  this->RenderWindow->Render();
}

<|endoftext|>


<commit_before>#include "opengl_properties.h"

int
main (void)
{
	print_opengl_properties();
}
<commit_msg>Fixed Illegal instruction bug<commit_after>#include "opengl_properties.h"
#include <GL/glew.h>
#include <SDL/SDL.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>

void
init_opengl ()
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(20.0f);
}

void
quit (int return_code)
{
  SDL_Quit();
	exit(return_code);
}

void
init_sdl ()
{
  const SDL_VideoInfo *video_info;

  if (SDL_Init( SDL_INIT_VIDEO ) < 0)
  {
    fprintf(stderr, "Video initialization failed: %s", SDL_GetError());
    quit(1);
  }

  video_info = SDL_GetVideoInfo();
  if (!video_info)
  {
    fprintf(stderr, "Video info query failed: %s", SDL_GetError());
    quit(1);
  }

  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0);

  SDL_Surface *surface = SDL_SetVideoMode(600, 600, 32,
	    SDL_OPENGL | SDL_GL_DOUBLEBUFFER);

  if (!surface)
  {
    fprintf(stderr, "Video mode set failed: %s", SDL_GetError());
    quit(1);
  }
}

void
init_extensions ()
{
	bool vbo_capable = false;

  GLenum err = glewInit();
  if (err != GLEW_OK)
  {
    printf("GLEW initialization error: %s\n", glewGetErrorString(err));
    return;
  }

  vbo_capable = GL_ARB_vertex_buffer_object;
}

int
main (int argc, char *argv[])
{
	init_sdl();
	print_opengl_properties();
	quit(0);
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "namenode_info.h"

#include "common/util.h"
#include "common/logging.h"

#include <sstream>
#include <utility>
#include <future>
#include <memory>

namespace hdfs {

ResolvedNamenodeInfo& ResolvedNamenodeInfo::operator=(const NamenodeInfo &info) {
  nameservice = info.nameservice;
  name = info.name;
  uri = info.uri;
  return *this;
}

std::string ResolvedNamenodeInfo::str() const {
  std::stringstream ss;
  ss << "ResolvedNamenodeInfo {nameservice: " << nameservice << ", name: " << name << ", uri: " << uri.str();
  ss << ", host: " << uri.get_host();
  auto port = uri.get_port();
  if(port)
    ss << ", port: " << port.value();
  else
    ss << ", port: unable to parse";

  ss << ", scheme: " << uri.get_scheme();

  ss << " [";
  for(unsigned int i=0;i<endpoints.size();i++)
    ss << endpoints[i] << " ";
  ss << "] }";

  return ss.str();
}

bool ResolveInPlace(::asio::io_service *ioservice, ResolvedNamenodeInfo &info) {
  // this isn't very memory friendly, but if it needs to be called often there are bigger issues at hand
  info.endpoints.clear();
  std::vector<ResolvedNamenodeInfo> resolved = BulkResolve(ioservice, {info});
  if(resolved.size() != 1)
    return false;

  info.endpoints = resolved[0].endpoints;
  if(info.endpoints.size() == 0)
    return false;
  return true;
}

typedef std::vector<asio::ip::tcp::endpoint> endpoint_vector;

// RAII wrapper
class ScopedResolver {
 private:
  ::asio::io_service *io_service_;
  std::string host_;
  std::string port_;
  ::asio::ip::tcp::resolver::query query_;
  ::asio::ip::tcp::resolver resolver_;
  endpoint_vector endpoints_;

  // Caller blocks on access if resolution isn't finished
  std::shared_ptr<std::promise<Status>> result_status_;
 public:
  ScopedResolver(::asio::io_service *service, const std::string &host, const std::string &port) :
        io_service_(service), host_(host), port_(port), query_(host, port), resolver_(*io_service_)
  {
    if(!io_service_)
      LOG_ERROR(kAsyncRuntime, << "ScopedResolver@" << this << " passed nullptr to io_service");
  }

  ~ScopedResolver() {
    resolver_.cancel();
  }

  bool BeginAsyncResolve() {
    // result_status_ would only exist if this was previously called.  Invalid state.
    if(result_status_) {
      LOG_ERROR(kAsyncRuntime, << "ScopedResolver@" << this << "::BeginAsyncResolve invalid call: may only be called once per instance");
      return false;
    } else if(!io_service_) {
      LOG_ERROR(kAsyncRuntime, << "ScopedResolver@" << this << "::BeginAsyncResolve invalid call: null io_service");
      return false;
    }

    // Now set up the promise, set it in async_resolve's callback
    result_status_ = std::make_shared<std::promise<Status>>();

    // Callback to pull a copy of endpoints out of resolver and set promise
    auto callback = [this](const asio::error_code &ec, ::asio::ip::tcp::resolver::iterator out) {
      if(!ec) {
        std::copy(out, ::asio::ip::tcp::resolver::iterator(), std::back_inserter(endpoints_));
      }
      result_status_->set_value( ToStatus(ec) );
    };
    resolver_.async_resolve(query_, callback);
    return true;
  }

  Status Join() {
    if(!result_status_) {
      std::ostringstream errmsg;
      errmsg <<  "ScopedResolver@" << this << "Join invalid call: promise never set";
      return Status::InvalidArgument(errmsg.str().c_str());
    }

    std::future<Status> future_result = result_status_->get_future();
    Status res = future_result.get();
    return res;
  }

  endpoint_vector GetEndpoints() {
    // Explicitly return by value to decouple lifecycles.
    return endpoints_;
  }
};

std::vector<ResolvedNamenodeInfo> BulkResolve(::asio::io_service *ioservice, const std::vector<NamenodeInfo> &nodes) {
  std::vector< std::unique_ptr<ScopedResolver> > resolvers;
  resolvers.reserve(nodes.size());

  std::vector<ResolvedNamenodeInfo> resolved_info;
  resolved_info.reserve(nodes.size());

  for(unsigned int i=0; i<nodes.size(); i++) {
    std::string host = nodes[i].get_host();
    std::string port = nodes[i].get_port();

    resolvers.emplace_back(new ScopedResolver(ioservice, host, port));
    resolvers[i]->BeginAsyncResolve();
  }

  // Join all async operations
  for(unsigned int i=0; i < resolvers.size(); i++) {
    Status asyncReturnStatus = resolvers[i]->Join();

    ResolvedNamenodeInfo info;
    info = nodes[i];

    if(asyncReturnStatus.ok()) {
      // Copy out endpoints if things went well
      info.endpoints = resolvers[i]->GetEndpoints();
    } else {
      LOG_ERROR(kAsyncRuntime, << "Unabled to resolve endpoints for host: " << nodes[i].get_host()
                                                               << " port: " << nodes[i].get_port());
    }

    resolved_info.push_back(info);
  }
  return resolved_info;
}

}
<commit_msg>HDFS-11436: libhdfs++: Fix race condition in ScopedResolver.  Contributed by James Clampffer.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "namenode_info.h"

#include "common/util.h"
#include "common/logging.h"

#include <sstream>
#include <utility>
#include <future>
#include <memory>

namespace hdfs {

ResolvedNamenodeInfo& ResolvedNamenodeInfo::operator=(const NamenodeInfo &info) {
  nameservice = info.nameservice;
  name = info.name;
  uri = info.uri;
  return *this;
}

std::string ResolvedNamenodeInfo::str() const {
  std::stringstream ss;
  ss << "ResolvedNamenodeInfo {nameservice: " << nameservice << ", name: " << name << ", uri: " << uri.str();
  ss << ", host: " << uri.get_host();
  auto port = uri.get_port();
  if(port)
    ss << ", port: " << port.value();
  else
    ss << ", port: unable to parse";

  ss << ", scheme: " << uri.get_scheme();

  ss << " [";
  for(unsigned int i=0;i<endpoints.size();i++)
    ss << endpoints[i] << " ";
  ss << "] }";

  return ss.str();
}

bool ResolveInPlace(::asio::io_service *ioservice, ResolvedNamenodeInfo &info) {
  // this isn't very memory friendly, but if it needs to be called often there are bigger issues at hand
  info.endpoints.clear();
  std::vector<ResolvedNamenodeInfo> resolved = BulkResolve(ioservice, {info});
  if(resolved.size() != 1)
    return false;

  info.endpoints = resolved[0].endpoints;
  if(info.endpoints.size() == 0)
    return false;
  return true;
}

typedef std::vector<asio::ip::tcp::endpoint> endpoint_vector;

// RAII wrapper
class ScopedResolver {
 private:
  ::asio::io_service *io_service_;
  std::string host_;
  std::string port_;
  ::asio::ip::tcp::resolver::query query_;
  ::asio::ip::tcp::resolver resolver_;
  endpoint_vector endpoints_;

  // Caller blocks on access if resolution isn't finished
  std::shared_ptr<std::promise<Status>> result_status_;
 public:
  ScopedResolver(::asio::io_service *service, const std::string &host, const std::string &port) :
        io_service_(service), host_(host), port_(port), query_(host, port), resolver_(*io_service_)
  {
    if(!io_service_)
      LOG_ERROR(kAsyncRuntime, << "ScopedResolver@" << this << " passed nullptr to io_service");
  }

  ~ScopedResolver() {
    resolver_.cancel();
  }

  bool BeginAsyncResolve() {
    // result_status_ would only exist if this was previously called.  Invalid state.
    if(result_status_) {
      LOG_ERROR(kAsyncRuntime, << "ScopedResolver@" << this << "::BeginAsyncResolve invalid call: may only be called once per instance");
      return false;
    } else if(!io_service_) {
      LOG_ERROR(kAsyncRuntime, << "ScopedResolver@" << this << "::BeginAsyncResolve invalid call: null io_service");
      return false;
    }

    // Now set up the promise, set it in async_resolve's callback
    result_status_ = std::make_shared<std::promise<Status>>();
    std::shared_ptr<std::promise<Status>> shared_result = result_status_;

    // Callback to pull a copy of endpoints out of resolver and set promise
    auto callback = [this, shared_result](const asio::error_code &ec, ::asio::ip::tcp::resolver::iterator out) {
      if(!ec) {
        std::copy(out, ::asio::ip::tcp::resolver::iterator(), std::back_inserter(endpoints_));
      }
      shared_result->set_value( ToStatus(ec) );
    };
    resolver_.async_resolve(query_, callback);
    return true;
  }

  Status Join() {
    if(!result_status_) {
      std::ostringstream errmsg;
      errmsg <<  "ScopedResolver@" << this << "Join invalid call: promise never set";
      return Status::InvalidArgument(errmsg.str().c_str());
    }

    std::future<Status> future_result = result_status_->get_future();
    Status res = future_result.get();
    return res;
  }

  endpoint_vector GetEndpoints() {
    // Explicitly return by value to decouple lifecycles.
    return endpoints_;
  }
};

std::vector<ResolvedNamenodeInfo> BulkResolve(::asio::io_service *ioservice, const std::vector<NamenodeInfo> &nodes) {
  std::vector< std::unique_ptr<ScopedResolver> > resolvers;
  resolvers.reserve(nodes.size());

  std::vector<ResolvedNamenodeInfo> resolved_info;
  resolved_info.reserve(nodes.size());

  for(unsigned int i=0; i<nodes.size(); i++) {
    std::string host = nodes[i].get_host();
    std::string port = nodes[i].get_port();

    resolvers.emplace_back(new ScopedResolver(ioservice, host, port));
    resolvers[i]->BeginAsyncResolve();
  }

  // Join all async operations
  for(unsigned int i=0; i < resolvers.size(); i++) {
    Status asyncReturnStatus = resolvers[i]->Join();

    ResolvedNamenodeInfo info;
    info = nodes[i];

    if(asyncReturnStatus.ok()) {
      // Copy out endpoints if things went well
      info.endpoints = resolvers[i]->GetEndpoints();
    } else {
      LOG_ERROR(kAsyncRuntime, << "Unabled to resolve endpoints for host: " << nodes[i].get_host()
                                                               << " port: " << nodes[i].get_port());
    }

    resolved_info.push_back(info);
  }
  return resolved_info;
}

}
<|endoftext|>


<commit_before>
#include <osgParticle/ParticleSystemUpdater>

#include <osg/ref_ptr>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>

bool  PSU_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool  PSU_writeLocalData(const osg::Object &obj, osgDB::Output &fr);

osgDB::RegisterDotOsgWrapperProxy PSU_Proxy
(
    new osgParticle::ParticleSystemUpdater,
    "ParticleSystemUpdater",
    "Object Node ParticleSystemUpdater",
    PSU_readLocalData,
    PSU_writeLocalData
);

bool PSU_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
    osgParticle::ParticleSystemUpdater &myobj = static_cast<osgParticle::ParticleSystemUpdater &>(obj);
    bool itAdvanced = false;

    osg::ref_ptr<osgParticle::ParticleSystem> proto = new osgParticle::ParticleSystem;
    osgParticle::ParticleSystem *ps = static_cast<osgParticle::ParticleSystem *>(fr.readObjectOfType(*proto));
    if (ps) {
        myobj.addParticleSystem(ps);
        itAdvanced = true;
    }

    return itAdvanced;
}

bool PSU_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
{
    const osgParticle::ParticleSystemUpdater &myobj = static_cast<const osgParticle::ParticleSystemUpdater &>(obj);

    for (int i=0; i<myobj.getNumParticleSystems(); ++i) {
        fw.writeObject(*myobj.getParticleSystem(i));
    }

    return true;
}
<commit_msg>Warnings fix for VS7.0 from Mike Weiblen<commit_after>
#include <osgParticle/ParticleSystemUpdater>

#include <osg/ref_ptr>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>

bool  PSU_readLocalData(osg::Object &obj, osgDB::Input &fr);
bool  PSU_writeLocalData(const osg::Object &obj, osgDB::Output &fr);

osgDB::RegisterDotOsgWrapperProxy PSU_Proxy
(
    new osgParticle::ParticleSystemUpdater,
    "ParticleSystemUpdater",
    "Object Node ParticleSystemUpdater",
    PSU_readLocalData,
    PSU_writeLocalData
);

bool PSU_readLocalData(osg::Object &obj, osgDB::Input &fr)
{
    osgParticle::ParticleSystemUpdater &myobj = static_cast<osgParticle::ParticleSystemUpdater &>(obj);
    bool itAdvanced = false;

    osg::ref_ptr<osgParticle::ParticleSystem> proto = new osgParticle::ParticleSystem;
    osgParticle::ParticleSystem *ps = static_cast<osgParticle::ParticleSystem *>(fr.readObjectOfType(*proto));
    if (ps) {
        myobj.addParticleSystem(ps);
        itAdvanced = true;
    }

    return itAdvanced;
}

bool PSU_writeLocalData(const osg::Object &obj, osgDB::Output &fw)
{
    const osgParticle::ParticleSystemUpdater &myobj = static_cast<const osgParticle::ParticleSystemUpdater &>(obj);

    for (unsigned int i=0; i<myobj.getNumParticleSystems(); ++i) {
        fw.writeObject(*myobj.getParticleSystem(i));
    }

    return true;
}
<|endoftext|>