<commit_before>#include "Settings.h"
#include "DRMSetupWizard.h"

#include <QLayout>
#include <QGroupBox>

/** Settings constructor
* Initialize the settings UI
* \param p Inherited palette configuration for setting StyleSheets.
* \param parent Pointer to parent widget.
*/

Settings::Settings(QSettings* p, QWidget* parent) : QWidget(parent) //,ui(new Ui::Settings)
{
    QFont buttonFont("SourceSansPro", 9);
    QVBoxLayout* vertlayout = new QVBoxLayout(this);
    this->setLayout(vertlayout);
    this->setStyleSheet("QPushButton {"
                                "color: " + p->value("Primary/LightText").toString() + "; "
                                "background-color: " + p->value("Primary/DarkElement").toString() + "; "
                                "border: none;}"
                                "QPushButton:hover {"
                                "background-color: " + p->value("Primary/InactiveSelection").toString() + ";} "
                                "color: " + p->value("Primary/LightText").toString() + ";");
    QGroupBox* userSettingsBox = new QGroupBox();
    vertlayout->addWidget(userSettingsBox);

    QHBoxLayout* horlayout = new QHBoxLayout(this);
    vertlayout->addLayout(horlayout);

    //Client Settings
    QGroupBox* clientSettingsBox = new QGroupBox();
    horlayout->addWidget(clientSettingsBox);
    QVBoxLayout* clientBoxLayout = new QVBoxLayout();
    clientSettingsBox->setLayout(clientBoxLayout);

    QPushButton* wizardButton = new QPushButton();
    wizardButton->setFont(buttonFont);
    wizardButton->setText("Add Games to Ascension");
    clientBoxLayout->addWidget(wizardButton);

    QPushButton* clearDatabaseButton = new QPushButton();
    clearDatabaseButton->setFont(buttonFont);
    clearDatabaseButton->setText("Clear Database");
    clientBoxLayout->addWidget(clearDatabaseButton);

    //End Client Settings

    //Style Settings
    QGroupBox* styleSettingsBox = new QGroupBox();
    horlayout->addWidget(styleSettingsBox);
    QVBoxLayout* styleBoxLayout = new QVBoxLayout();
    styleSettingsBox->setLayout(styleBoxLayout);

    accentButton = new QPushButton();
    accentButton->setFont(buttonFont);
    accentButton->setStyleSheet("QPushButton{ background-color: " + p->value("Accent/LightAccent").toString() + ";}");
    accentButton_2 = new QPushButton();
    accentButton_2->setFont(buttonFont);
    accentButton_2->setStyleSheet("QPushButton{ background-color: " + p->value("Accent/MediumAccent").toString() + ";}");
    accentButton_3 = new QPushButton();
    accentButton_3->setFont(buttonFont);
    accentButton_3->setStyleSheet("QPushButton{ background-color: " + p->value("Accent/DarkAccent").toString() + ";}");
    QPushButton* resetAccents = new QPushButton();
    resetAccents->setFont(buttonFont);
    resetAccents->setText("Reset Colors to Default");

    styleBoxLayout->addWidget(accentButton);
    styleBoxLayout->addWidget(accentButton_2);
    styleBoxLayout->addWidget(accentButton_3);
    styleBoxLayout->addWidget(resetAccents);
    //End Style Settings

    QGroupBox* testSettingsBox = new QGroupBox();
    horlayout->addWidget(testSettingsBox);

    userSettingsBox->setStyleSheet("QGroupBox{ background-color: " + p->value("Primary/SecondaryBase").toString() + ";}");
    clientSettingsBox->setStyleSheet("QGroupBox{ background-color: " + p->value("Primary/SecondaryBase").toString() + ";}");
    styleSettingsBox->setStyleSheet("QGroupBox{ background-color: " + p->value("Primary/SecondaryBase").toString() + ";}");
    testSettingsBox->setStyleSheet("QGroupBox{ background-color: " + p->value("Primary/SecondaryBase").toString() + ";}");

    connect(wizardButton, SIGNAL(clicked()), this, SLOT(rerunGameWizard()));
    connect(clearDatabaseButton, SIGNAL(clicked()), this, SLOT(clearDatabase()));
    connect(accentButton, SIGNAL(clicked()), this, SLOT(setLightAccent()));
    connect(accentButton_2, SIGNAL(clicked()), this, SLOT(setMediumAccent()));
    connect(accentButton_3, SIGNAL(clicked()), this, SLOT(setDarkAccent()));
    connect(resetAccents, SIGNAL(clicked()), this, SLOT(resetAccents()));

    if (!db.init())
    {
        QMessageBox error;
        error.critical(0, "Error!", "An error occured while trying to load the database.");
        exit(EXIT_FAILURE);
    }
}

/** Event handler for Wizard Button
* Runs setup wizard on click
*/
void Settings::rerunGameWizard()
{
	DRMSetupWizard* wiz = new DRMSetupWizard();
	wiz->show();
}

void Settings::setLightAccent()
{
    QColor color = QColorDialog::getColor(Qt::white);
    updateAccent(1,color);
}

void Settings::setMediumAccent()
{
    QColor color = QColorDialog::getColor(Qt::white);
    updateAccent(2,color);
}

void Settings::setDarkAccent()
{
    QColor color = QColorDialog::getColor(Qt::white);
    updateAccent(3,color);
}

void Settings::resetAccents()
{
    QSettings palette(QSettings::IniFormat, QSettings::UserScope, "Project Ascension", "palette");

    if (palette.isWritable())
    {
        palette.beginGroup("Primary");

        palette.setValue("ActiveElement", "#FFFFFF");
        palette.setValue("InactiveSelection", "#686868");
        palette.setValue("HoverSelection", "#ADADAD");
        palette.setValue("DarkElement", "#4D5250");
        palette.setValue("LightText", "#FFFFFF");
        palette.setValue("DarkText", "#242424");
        palette.setValue("SubText", "#B2B4B3");
        palette.setValue("PrimaryBase", "#282828");
        palette.setValue("SecondaryBase", "#1F1F1F");
        palette.setValue("TertiaryBase", "#131313");
        palette.setValue("DarkestBase", "#0F0F0F");
        palette.endGroup();

        palette.beginGroup("Accent");

        palette.setValue("LightAccent", "#E58F12");
        palette.setValue("MediumAccent", "#895f06");
        palette.setValue("DarkAccent", "#6a4a05");
        palette.endGroup();
    }
    accentButton->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/LightAccent").toString() + ";}");
    accentButton_2->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/MediumAccent").toString() + ";}");
    accentButton_3->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/DarkAccent").toString() + ";}");
}

void Settings::updateAccent(int accent, QColor color)
{
    QSettings palette(QSettings::IniFormat, QSettings::UserScope, "Project Ascension", "palette");
    if (palette.isWritable())
    {
        palette.beginGroup("Primary");
        palette.endGroup();
        palette.beginGroup("Accent");
        if(accent == 1) palette.setValue("LightAccent", color.name());
        if(accent == 2) palette.setValue("MediumAccent", color.name());
        if(accent == 3) palette.setValue("DarkAccent", color.name());
        palette.endGroup();
    }
    if(accent == 1) accentButton->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/LightAccent").toString() + ";}");
    if(accent == 2) accentButton_2->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/MediumAccent").toString() + ";}");
    if(accent == 3) accentButton_3->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/DarkAccent").toString() + ";}");
}

void Settings::clearDatabase()
{
    int ret = QMessageBox(QMessageBox::Question, "Deleting Database", "Proceeding will delete the database, the database will be non-recoverable. Proceed?", QMessageBox::Yes | QMessageBox::No).exec();
    switch (ret)
    {
    case QMessageBox::Yes:
        db.reset();
        break;
    case QMessageBox::No:
        break;
    default:
        break;
    }
}

Settings::~Settings()
{
}
<commit_msg>Settings Widget:<commit_after>#include "Settings.h"
#include "DRMSetupWizard.h"

#include <QLayout>
#include <QGroupBox>

/** Settings constructor
* Initialize the settings UI
* \param p Inherited palette configuration for setting StyleSheets.
* \param parent Pointer to parent widget.
*/

Settings::Settings(QSettings* p, QWidget* parent) : QWidget(parent) //,ui(new Ui::Settings)
{
    QFont buttonFont("SourceSansPro", 9);
    QVBoxLayout* vertlayout = new QVBoxLayout(this);
    this->setLayout(vertlayout);
    this->setStyleSheet("QPushButton {"
                                "color: " + p->value("Primary/LightText").toString() + "; "
                                "background-color: " + p->value("Primary/DarkElement").toString() + "; "
                                "border: none;}"
                                "QPushButton:hover {"
                                "background-color: " + p->value("Primary/InactiveSelection").toString() + ";} "
                                "QGroupBox { color: " + p->value("Primary/LightText").toString() + ";}");
    QGroupBox* userSettingsBox = new QGroupBox();
    vertlayout->addWidget(userSettingsBox);
    userSettingsBox->setTitle("User Settings");

    QHBoxLayout* horlayout = new QHBoxLayout(this);
    vertlayout->addLayout(horlayout);

    //Client Settings
    QGroupBox* clientSettingsBox = new QGroupBox();
    horlayout->addWidget(clientSettingsBox);
    QVBoxLayout* clientBoxLayout = new QVBoxLayout();
    clientSettingsBox->setLayout(clientBoxLayout);
    clientSettingsBox->setTitle("Client Settings");

    QPushButton* wizardButton = new QPushButton();
    wizardButton->setFont(buttonFont);
    wizardButton->setText("Add Games to Ascension");
    clientBoxLayout->addWidget(wizardButton);

    QPushButton* clearDatabaseButton = new QPushButton();
    clearDatabaseButton->setFont(buttonFont);
    clearDatabaseButton->setText("Clear Database");
    clientBoxLayout->addWidget(clearDatabaseButton);
    //End Client Settings

    //Style Settings
    QGroupBox* styleSettingsBox = new QGroupBox();
    horlayout->addWidget(styleSettingsBox);
    QVBoxLayout* styleBoxLayout = new QVBoxLayout();
    styleSettingsBox->setLayout(styleBoxLayout);
    styleSettingsBox->setTitle("Style Settings");

    accentButton = new QPushButton();
    accentButton->setFont(buttonFont);
    accentButton->setStyleSheet("QPushButton{ background-color: " + p->value("Accent/LightAccent").toString() + ";""}");
    accentButton->setText("Set Light Accent");
    accentButton_2 = new QPushButton();
    accentButton_2->setFont(buttonFont);
    accentButton_2->setStyleSheet("QPushButton{ background-color: " + p->value("Accent/MediumAccent").toString() + ";}");
    accentButton_2->setText("Set Medium Accent");
    accentButton_3 = new QPushButton();
    accentButton_3->setFont(buttonFont);
    accentButton_3->setStyleSheet("QPushButton{ background-color: " + p->value("Accent/DarkAccent").toString() + ";}");
    accentButton_3->setText("Set Dark Accent");
    QPushButton* resetAccents = new QPushButton();
    resetAccents->setFont(buttonFont);
    resetAccents->setText("Reset Colors to Default");

    styleBoxLayout->addWidget(accentButton);
    styleBoxLayout->addWidget(accentButton_2);
    styleBoxLayout->addWidget(accentButton_3);
    styleBoxLayout->addWidget(resetAccents);
    //End Style Settings

    QGroupBox* testSettingsBox = new QGroupBox();
    horlayout->addWidget(testSettingsBox);

    userSettingsBox->setStyleSheet("QGroupBox{ background-color: " + p->value("Primary/SecondaryBase").toString() + ";}");
    clientSettingsBox->setStyleSheet("QGroupBox{ background-color: " + p->value("Primary/SecondaryBase").toString() + ";}");
    styleSettingsBox->setStyleSheet("QGroupBox{ background-color: " + p->value("Primary/SecondaryBase").toString() + ";}");
    testSettingsBox->setStyleSheet("QGroupBox{ background-color: " + p->value("Primary/SecondaryBase").toString() + ";}");

    connect(wizardButton, SIGNAL(clicked()), this, SLOT(rerunGameWizard()));
    connect(clearDatabaseButton, SIGNAL(clicked()), this, SLOT(clearDatabase()));
    connect(accentButton, SIGNAL(clicked()), this, SLOT(setLightAccent()));
    connect(accentButton_2, SIGNAL(clicked()), this, SLOT(setMediumAccent()));
    connect(accentButton_3, SIGNAL(clicked()), this, SLOT(setDarkAccent()));
    connect(resetAccents, SIGNAL(clicked()), this, SLOT(resetAccents()));

    if (!db.init())
    {
        QMessageBox error;
        error.critical(0, "Error!", "An error occured while trying to load the database.");
        exit(EXIT_FAILURE);
    }
}

/** Event handler for Wizard Button
* Runs setup wizard on click
*/
void Settings::rerunGameWizard()
{
	DRMSetupWizard* wiz = new DRMSetupWizard();
	wiz->show();
}

void Settings::setLightAccent()
{
    QColor color = QColorDialog::getColor(Qt::white);
    updateAccent(1,color);
}

void Settings::setMediumAccent()
{
    QColor color = QColorDialog::getColor(Qt::white);
    updateAccent(2,color);
}

void Settings::setDarkAccent()
{
    QColor color = QColorDialog::getColor(Qt::white);
    updateAccent(3,color);
}

void Settings::resetAccents()
{
    QSettings palette(QSettings::IniFormat, QSettings::UserScope, "Project Ascension", "palette");

    if (palette.isWritable())
    {
        palette.beginGroup("Primary");

        palette.setValue("ActiveElement", "#FFFFFF");
        palette.setValue("InactiveSelection", "#686868");
        palette.setValue("HoverSelection", "#ADADAD");
        palette.setValue("DarkElement", "#4D5250");
        palette.setValue("LightText", "#FFFFFF");
        palette.setValue("DarkText", "#242424");
        palette.setValue("SubText", "#B2B4B3");
        palette.setValue("PrimaryBase", "#282828");
        palette.setValue("SecondaryBase", "#1F1F1F");
        palette.setValue("TertiaryBase", "#131313");
        palette.setValue("DarkestBase", "#0F0F0F");
        palette.endGroup();

        palette.beginGroup("Accent");

        palette.setValue("LightAccent", "#E58F12");
        palette.setValue("MediumAccent", "#895f06");
        palette.setValue("DarkAccent", "#6a4a05");
        palette.endGroup();
    }
    accentButton->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/LightAccent").toString() + ";}");
    accentButton_2->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/MediumAccent").toString() + ";}");
    accentButton_3->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/DarkAccent").toString() + ";}");
}

void Settings::updateAccent(int accent, QColor color)
{
    QSettings palette(QSettings::IniFormat, QSettings::UserScope, "Project Ascension", "palette");
    if (palette.isWritable())
    {
        palette.beginGroup("Primary");
        palette.endGroup();
        palette.beginGroup("Accent");
        if(accent == 1) palette.setValue("LightAccent", color.name());
        if(accent == 2) palette.setValue("MediumAccent", color.name());
        if(accent == 3) palette.setValue("DarkAccent", color.name());
        palette.endGroup();
    }
    if(accent == 1) accentButton->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/LightAccent").toString() + ";}");
    if(accent == 2) accentButton_2->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/MediumAccent").toString() + ";}");
    if(accent == 3) accentButton_3->setStyleSheet("QPushButton{ background-color: " + palette.value("Accent/DarkAccent").toString() + ";}");
}

void Settings::clearDatabase()
{
    int ret = QMessageBox(QMessageBox::Question, "Deleting Database", "Proceeding will delete the database, the database will be non-recoverable. Proceed?", QMessageBox::Yes | QMessageBox::No).exec();
    switch (ret)
    {
    case QMessageBox::Yes:
        db.reset();
        break;
    case QMessageBox::No:
        break;
    default:
        break;
    }
}

Settings::~Settings()
{
}
<|endoftext|>


<commit_before>/*
 *  qiaffine.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>

#include "itkImage.h"
#include "itkVersor.h"
#include "itkVersorRigid3DTransform.h"
#include "itkCenteredAffineTransform.h"
#include "itkTransformFileWriter.h"

#include "QI/Util.h"
#include "QI/IO.h"
#include "QI/Args.h"

using namespace std;

int main(int argc, char **argv) {
    Eigen::initParallel();

    args::ArgumentParser parser("Applies simple affine transformations to images by manipulating the header\n"
        "transforms. If an output file is not specified, the input file will be\n"
        "overwritten.\n"
        "http://github.com/spinicist/QUIT");

    args::Positional<std::string> source_path(parser, "SOURCE", "Source file");
    args::Positional<std::string> dest_path(parser, "DEST", "Destination file");

    args::HelpFlag help(parser, "HELP", "Show this help menu", {'h', "help"});
    args::Flag     verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"});
    args::Flag     center(parser, "CENTER", "Set the origin to the center of the image", {'c', "center"});
    args::ValueFlag<std::string> tfm_path(parser, "TFM", "Write out the transformation to a file", {'t', "tfm"});
    args::ValueFlag<double> scale(parser, "SCALE", "Scale by a constant", {'s', "scale"});
    args::ValueFlag<double> offX(parser, "OFF_X", "Translate origin in X direction", {"offX"});
    args::ValueFlag<double> offY(parser, "OFF_Y", "Translate origin in Y direction", {"offY"});
    args::ValueFlag<double> offZ(parser, "OFF_Z", "Translate origin in Z direction", {"offZ"});
    args::ValueFlag<double> rotX(parser, "ROT_X", "Rotate about X-axis by angle (degrees)", {"rotX"});
    args::ValueFlag<double> rotY(parser, "ROT_Y", "Rotate about Y-axis by angle (degrees)", {"rotY"});
    args::ValueFlag<double> rotZ(parser, "ROT_Z", "Rotate about Z-axis by angle (degrees)", {"rotZ"});

    QI::ParseArgs(parser, argc, argv);

    auto image = QI::ReadImage<QI::SeriesF>(QI::CheckPos(source_path));

    QI::SeriesF::DirectionType fullDir = image->GetDirection();
    QI::SeriesF::SpacingType fullSpacing = image->GetSpacing();
    QI::SeriesF::PointType fullOrigin = image->GetOrigin();
    QI::SeriesF::SizeType fullSize = image->GetLargestPossibleRegion().GetSize();
    QI::VolumeF::DirectionType direction;
    QI::VolumeF::SpacingType spacing;

    typedef itk::CenteredAffineTransform<double, 3> TAffine;
    TAffine::OutputVectorType origin;
    QI::VolumeF::SizeType size;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            direction[i][j] = fullDir[i][j];
        }
        origin[i] = fullOrigin[i];
        spacing[i] = fullSpacing[i];
        size[i] = fullSize[i];
    }
    auto img_tfm = TAffine::New();
    itk::Versor<double> vd; vd.Set(direction);
    auto vt = itk::VersorRigid3DTransform<double>::New();
    vt->SetRotation(vd);
    img_tfm->Compose(vt);
    img_tfm->Scale(spacing);
    img_tfm->Translate(origin);

    auto tfm = TAffine::New();
    if (scale) {
        if (verbose) cout << "Scaling by factor " << scale.Get() << endl;
        tfm->Scale(scale.Get());
    }
    if (rotX != 0.0) {
        if (verbose) cout << "Rotating image by " << rotX.Get() << " around X axis." << endl;
        tfm->Rotate(1,2,rotX.Get() * M_PI / 180.0);
    }
    if (rotY != 0.0) {
        if (verbose) cout << "Rotating image by " << rotY.Get() << " around X axis." << endl;
        tfm->Rotate(2,0,rotY.Get() * M_PI / 180.0);
    }
    if (rotZ != 0.0) {
        if (verbose) cout << "Rotating image by " << rotZ.Get() << " around X axis." << endl;
        tfm->Rotate(0,1,rotZ.Get() * M_PI / 180.0);
    }
    itk::Versor<double>::VectorType offset; offset.Fill(0);
    if (center) {
        for (int i = 0; i < 3; i++) {
            offset[i] = origin[i]-spacing[i]*size[i] / 2;
        }
        if (verbose) std::cout << "Centering image" << std::endl;
        tfm->Translate(-offset);
    } else if (offX || offY || offZ) {
        offset[0] = offX.Get();
        offset[1] = offY.Get();
        offset[2] = offZ.Get();
        if (verbose) std::cout << "Translating by: " << offset << std::endl;
        tfm->Translate(-offset);
    }

    if (tfm_path) { // Output the transform file
        auto writer = itk::TransformFileWriterTemplate<double>::New();
        writer->SetInput(tfm);
        writer->SetFileName(tfm_path.Get());
        writer->Update();
    }

    img_tfm->Compose(tfm);
    itk::CenteredAffineTransform<double, 3>::MatrixType fmat = img_tfm->GetMatrix();
    for (int i = 0; i < 3; i++) {
        fullOrigin[i] = img_tfm->GetOffset()[i];
    }
    for (int j = 0; j < 3; j++) {
        double scale = 0.;
        for (int i = 0; i < 3; i++) {
            scale += fmat[i][j]*fmat[i][j];
        }
        scale = sqrt(scale);

        fullSpacing[j] = scale;
        for (int i = 0; i < 3; i++) {
            fullDir[i][j] = fmat[i][j] / scale;
        }
    }
    image->SetDirection(fullDir);
    image->SetOrigin(fullOrigin);
    image->SetSpacing(fullSpacing);
    // Write out the edited file
    if (dest_path) {
        QI::WriteImage(image, dest_path.Get());
    } else {
        QI::WriteImage(image, source_path.Get());
    }
    return EXIT_SUCCESS;
}
<commit_msg>ENH: Now supports different data-types. BUG: Wasn't coping with axes swaps properly.<commit_after>/*
 *  qiaffine.cpp
 *
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>

#include "itkImage.h"
#include "itkVersor.h"
#include "itkVersorRigid3DTransform.h"
#include "itkCenteredAffineTransform.h"
#include "itkTransformFileWriter.h"

#include "QI/Util.h"
#include "QI/IO.h"
#include "QI/Args.h"

using namespace std;

/*
 * Declare arguments here so they are available to pipeline
 */
args::ArgumentParser parser("Applies simple affine transformations to images by manipulating the header\n"
    "transforms. If an output file is not specified, the input file will be\n"
    "overwritten.\n"
    "http://github.com/spinicist/QUIT");

args::Positional<std::string> source_path(parser, "SOURCE", "Source file");
args::Positional<std::string> dest_path(parser, "DEST", "Destination file");

args::HelpFlag help(parser, "HELP", "Show this help menu", {'h', "help"});
args::Flag     verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"});
args::Flag     center(parser, "CENTER", "Set the origin to the center of the image", {'c', "center"});
args::ValueFlag<std::string> tfm_path(parser, "TFM", "Write out the transformation to a file", {'t', "tfm"});
args::ValueFlag<double> scale(parser, "SCALE", "Scale by a constant", {'s', "scale"});
args::ValueFlag<double> offX(parser, "OFF_X", "Translate origin in X direction", {"offX"});
args::ValueFlag<double> offY(parser, "OFF_Y", "Translate origin in Y direction", {"offY"});
args::ValueFlag<double> offZ(parser, "OFF_Z", "Translate origin in Z direction", {"offZ"});
args::ValueFlag<double> rotX(parser, "ROT_X", "Rotate about X-axis by angle (degrees)", {"rotX"});
args::ValueFlag<double> rotY(parser, "ROT_Y", "Rotate about Y-axis by angle (degrees)", {"rotY"});
args::ValueFlag<double> rotZ(parser, "ROT_Z", "Rotate about Z-axis by angle (degrees)", {"rotZ"});

template<typename TImage>
int Pipeline() {
    auto image = QI::ReadImage<TImage>(QI::CheckPos(source_path));

    typename TImage::DirectionType fullDir = image->GetDirection();
    typename TImage::SpacingType fullSpacing = image->GetSpacing();
    typename TImage::PointType fullOrigin = image->GetOrigin();
    typename TImage::SizeType fullSize = image->GetLargestPossibleRegion().GetSize();
    QI::VolumeF::DirectionType direction;
    QI::VolumeF::SpacingType spacing;

    typedef itk::CenteredAffineTransform<double, 3> TAffine;
    TAffine::OutputVectorType origin;
    QI::VolumeF::SizeType size;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            direction[i][j] = fullDir[i][j];
        }
        origin[i] = fullOrigin[i];
        spacing[i] = fullSpacing[i];
        size[i] = fullSize[i];
    }

    auto img_tfm = TAffine::New();
    img_tfm->SetMatrix(direction);
    img_tfm->Scale(spacing);
    img_tfm->Translate(origin);
    if (verbose) std::cout << "Start transform:\n" << img_tfm->GetMatrix() << std::endl;
    auto tfm = TAffine::New();
    if (scale) {
        if (verbose) cout << "Scaling by factor " << scale.Get() << endl;
        tfm->Scale(scale.Get());
    }
    if (rotX != 0.0) {
        if (verbose) cout << "Rotating image by " << rotX.Get() << " around X axis." << endl;
        tfm->Rotate(1,2,rotX.Get() * M_PI / 180.0);
    }
    if (rotY != 0.0) {
        if (verbose) cout << "Rotating image by " << rotY.Get() << " around X axis." << endl;
        tfm->Rotate(2,0,rotY.Get() * M_PI / 180.0);
    }
    if (rotZ != 0.0) {
        if (verbose) cout << "Rotating image by " << rotZ.Get() << " around X axis." << endl;
        tfm->Rotate(0,1,rotZ.Get() * M_PI / 180.0);
    }
    itk::Versor<double>::VectorType offset; offset.Fill(0);
    if (center) {
        for (int i = 0; i < 3; i++) {
            offset[i] = origin[i]-spacing[i]*size[i] / 2;
        }
        if (verbose) std::cout << "Centering image" << std::endl;
        tfm->Translate(-offset);
    } else if (offX || offY || offZ) {
        offset[0] = offX.Get();
        offset[1] = offY.Get();
        offset[2] = offZ.Get();
        if (verbose) std::cout << "Translating by: " << offset << std::endl;
        tfm->Translate(-offset);
    }

    if (tfm_path) { // Output the transform file
        auto writer = itk::TransformFileWriterTemplate<double>::New();
        writer->SetInput(tfm);
        writer->SetFileName(tfm_path.Get());
        writer->Update();
    }

    img_tfm->Compose(tfm);
    itk::CenteredAffineTransform<double, 3>::MatrixType fmat = img_tfm->GetMatrix();
    if (verbose) std::cout << "Final transform:\n" << fmat << std::endl;
    for (int i = 0; i < 3; i++) {
        fullOrigin[i] = img_tfm->GetOffset()[i];
    }
    for (int j = 0; j < 3; j++) {
        double scale = 0.;
        for (int i = 0; i < 3; i++) {
            scale += fmat[i][j]*fmat[i][j];
        }
        scale = sqrt(scale);

        fullSpacing[j] = scale;
        for (int i = 0; i < 3; i++) {
            fullDir[i][j] = fmat[i][j] / scale;
        }
    }
    image->SetDirection(fullDir);
    image->SetOrigin(fullOrigin);
    image->SetSpacing(fullSpacing);
    // Write out the edited file
    if (dest_path) {
        QI::WriteImage(image, dest_path.Get());
    } else {
        QI::WriteImage(image, source_path.Get());
    }
    return EXIT_SUCCESS;
}

int main(int argc, char **argv) {
    QI::ParseArgs(parser, argc, argv);
    if (verbose) std::cout << "Reading header for: " << QI::CheckPos(source_path) << std::endl;
    auto header = itk::ImageIOFactory::CreateImageIO(source_path.Get().c_str(), itk::ImageIOFactory::ReadMode);
    header->SetFileName(source_path.Get());
    header->ReadImageInformation();
    auto dims  = header->GetNumberOfDimensions();
    auto dtype = header->GetComponentType();
    if (verbose) std::cout << "Datatype is " << header->GetComponentTypeAsString( dtype ) << std::endl;

    #define DIM_SWITCH( TYPE ) \
        switch (dims) { \
            case 3: return Pipeline<itk::Image< TYPE , 3 >>(); \
            case 4: return Pipeline<itk::Image< TYPE , 4 >>(); \
            default: QI_FAIL("Unsupported dimension: " << dims); return EXIT_FAILURE; \
        }

    switch (dtype) {
        case itk::ImageIOBase::UNKNOWNCOMPONENTTYPE: QI_FAIL("Unknown component type in image " << source_path);
        case itk::ImageIOBase::UCHAR:  DIM_SWITCH( unsigned char ); break;
        case itk::ImageIOBase::CHAR:   DIM_SWITCH( char ); break;
        case itk::ImageIOBase::USHORT: DIM_SWITCH( unsigned short ); break;
        case itk::ImageIOBase::SHORT:  DIM_SWITCH( short ); break;
        case itk::ImageIOBase::UINT:   DIM_SWITCH( unsigned int ); break;
        case itk::ImageIOBase::INT:    DIM_SWITCH( int ); break;
        case itk::ImageIOBase::ULONG:  DIM_SWITCH( unsigned long ); break;
        case itk::ImageIOBase::LONG:   DIM_SWITCH( long ); break;
        case itk::ImageIOBase::FLOAT:  DIM_SWITCH( float ); break;
        case itk::ImageIOBase::DOUBLE: DIM_SWITCH( double ); break;
    }
}
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

Licensed 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 "paddle/fluid/operators/sequence_ops/sequence_softmax_op.h"
#include <string>

namespace paddle {
namespace operators {

class SequenceSoftmaxOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("X"),
                   "Input(X) of SequenceSoftmaxOp should not be null.");
    PADDLE_ENFORCE(ctx->HasOutput("Out"),
                   "Output(Out) of SequenceSoftmaxOp should not be null.");

    ctx->ShareDim("X", /*->*/ "Out");
    ctx->ShareLoD("X", /*->*/ "Out");
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    // choose cudnn kernel if the runtime supported.
    bool use_cudnn = ctx.Attr<bool>("use_cudnn");
    bool runtime_cudnn_support = false;
#ifdef PADDLE_WITH_CUDA
    if (platform::is_gpu_place(ctx.GetPlace())) {
      auto& dev_ctx =
          ctx.template device_context<platform::CUDADeviceContext>();
      runtime_cudnn_support = dev_ctx.cudnn_handle() != nullptr ? true : false;
    }
#endif
    framework::LibraryType library_ = framework::LibraryType::kPlain;
    if (use_cudnn && runtime_cudnn_support) {
      library_ = framework::LibraryType::kCUDNN;
    }
    std::string data_format = ctx.Attr<std::string>("data_format");
    return framework::OpKernelType(
        ctx.Input<Tensor>("X")->type(), ctx.GetPlace(),
        framework::StringToDataLayout(data_format), library_);
  }
};

class SequenceSoftmaxOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X",
             "(LoDTensor) 1-D or 2-D input LoDTensor with the 2-nd dimension "
             "of length 1.");
    AddOutput("Out",
              "(LoDTensor) 1-D or 2-D output LoDTensor with the 2-nd dimension "
              "of length 1.");
    AddAttr<bool>(
        "use_cudnn",
        "(bool, default false) Only used in cudnn kernel, need install cudnn")
        .SetDefault(false);
    AddAttr<std::string>(
        "data_format",
        "(string, default NCHW) Only used in "
        "An optional string from: \"NHWC\", \"NCHW\". "
        "Defaults to \"NHWC\". Specify the data format of the output data, "
        "the input will be transformed automatically. ")
        .SetDefault("AnyLayout");
    AddComment(R"DOC(
Sequence Softmax Operator.

SequenceSoftmaxOp computes the softmax activation among all time-steps for each
sequence. The dimension of each time-step should be 1. Thus, the shape of
input Tensor can be either [N, 1] or [N], where N is the sum of the length
of all sequences.

The algorithm works as follows:

    for i-th sequence in a mini-batch:

$$
Out(X[lod[i]:lod[i+1]], :) = \
\frac{\exp(X[lod[i]:lod[i+1], :])} \
{\sum(\exp(X[lod[i]:lod[i+1], :]))}
$$

For example, for a mini-batch of 3 sequences with variable-length,
each containing 2, 3, 2 time-steps, the lod of which is [0, 2, 5, 7],
then softmax will be computed among X[0:2, :], X[2:5, :], X[5:7, :]
and N turns out to be 7.

)DOC");
  }
};

class SequenceSoftmaxGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("Out"),
                   "Input(Out) of SequenceSoftmaxGradOp should not be null.");
    PADDLE_ENFORCE(
        ctx->HasInput(framework::GradVarName("Out")),
        "Input(Out@GRAD) of SequenceSoftmaxGradOp should not be null.");
    PADDLE_ENFORCE(ctx->HasInput("X"),
                   "Input(X) of SequenceSoftmaxOp should not be null.");
    PADDLE_ENFORCE(ctx->HasOutput(framework::GradVarName("X")),
                   "Output(X@GRAD) of SequenceSoftmaxOp should not be null.");

    PADDLE_ENFORCE_EQ(
        ctx->GetInputDim("Out"),
        ctx->GetInputDim(framework::GradVarName("Out")),
        "Input(Out) and Input(Out@GRAD) of SequenceSoftmaxGradOp should be of "
        "the same shape.");

    ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("X"));
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    // choose cudnn kernel if the runtime supported.
    bool use_cudnn = ctx.Attr<bool>("use_cudnn");
    bool runtime_cudnn_support = false;
#ifdef PADDLE_WITH_CUDA
    if (platform::is_gpu_place(ctx.GetPlace())) {
      auto& dev_ctx =
          ctx.template device_context<platform::CUDADeviceContext>();
      runtime_cudnn_support = dev_ctx.cudnn_handle() != nullptr ? true : false;
    }
#endif
    framework::LibraryType library_ = framework::LibraryType::kPlain;
    if (use_cudnn && runtime_cudnn_support) {
      library_ = framework::LibraryType::kCUDNN;
    }
    std::string data_format = ctx.Attr<std::string>("data_format");
    return framework::OpKernelType(
        ctx.Input<Tensor>("X")->type(), ctx.GetPlace(),
        framework::StringToDataLayout(data_format), library_);
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(sequence_softmax, ops::SequenceSoftmaxOp,
                  ops::SequenceSoftmaxOpMaker,
                  paddle::framework::DefaultGradOpDescMaker<true>);
REGISTER_OPERATOR(sequence_softmax_grad, ops::SequenceSoftmaxGradOp);
REGISTER_OP_CPU_KERNEL(
    sequence_softmax,
    ops::SequenceSoftmaxKernel<paddle::platform::CPUDeviceContext, float>,
    ops::SequenceSoftmaxKernel<paddle::platform::CPUDeviceContext, double>);
REGISTER_OP_CPU_KERNEL(
    sequence_softmax_grad,
    ops::SequenceSoftmaxGradKernel<paddle::platform::CPUDeviceContext, float>,
    ops::SequenceSoftmaxGradKernel<paddle::platform::CPUDeviceContext, double>);
<commit_msg>refine sequence_softmax grad maker, test=develop (#20127)<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

Licensed 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 "paddle/fluid/operators/sequence_ops/sequence_softmax_op.h"
#include <string>

namespace paddle {
namespace operators {

class SequenceSoftmaxOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("X"),
                   "Input(X) of SequenceSoftmaxOp should not be null.");
    PADDLE_ENFORCE(ctx->HasOutput("Out"),
                   "Output(Out) of SequenceSoftmaxOp should not be null.");

    ctx->ShareDim("X", /*->*/ "Out");
    ctx->ShareLoD("X", /*->*/ "Out");
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    // choose cudnn kernel if the runtime supported.
    bool use_cudnn = ctx.Attr<bool>("use_cudnn");
    bool runtime_cudnn_support = false;
#ifdef PADDLE_WITH_CUDA
    if (platform::is_gpu_place(ctx.GetPlace())) {
      auto& dev_ctx =
          ctx.template device_context<platform::CUDADeviceContext>();
      runtime_cudnn_support = dev_ctx.cudnn_handle() != nullptr ? true : false;
    }
#endif
    framework::LibraryType library_ = framework::LibraryType::kPlain;
    if (use_cudnn && runtime_cudnn_support) {
      library_ = framework::LibraryType::kCUDNN;
    }
    std::string data_format = ctx.Attr<std::string>("data_format");
    return framework::OpKernelType(
        ctx.Input<Tensor>("X")->type(), ctx.GetPlace(),
        framework::StringToDataLayout(data_format), library_);
  }
};

class SequenceSoftmaxOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X",
             "(LoDTensor) 1-D or 2-D input LoDTensor with the 2-nd dimension "
             "of length 1.");
    AddOutput("Out",
              "(LoDTensor) 1-D or 2-D output LoDTensor with the 2-nd dimension "
              "of length 1.");
    AddAttr<bool>(
        "use_cudnn",
        "(bool, default false) Only used in cudnn kernel, need install cudnn")
        .SetDefault(false);
    AddAttr<std::string>(
        "data_format",
        "(string, default NCHW) Only used in "
        "An optional string from: \"NHWC\", \"NCHW\". "
        "Defaults to \"NHWC\". Specify the data format of the output data, "
        "the input will be transformed automatically. ")
        .SetDefault("AnyLayout");
    AddComment(R"DOC(
Sequence Softmax Operator.

SequenceSoftmaxOp computes the softmax activation among all time-steps for each
sequence. The dimension of each time-step should be 1. Thus, the shape of
input Tensor can be either [N, 1] or [N], where N is the sum of the length
of all sequences.

The algorithm works as follows:

    for i-th sequence in a mini-batch:

$$
Out(X[lod[i]:lod[i+1]], :) = \
\frac{\exp(X[lod[i]:lod[i+1], :])} \
{\sum(\exp(X[lod[i]:lod[i+1], :]))}
$$

For example, for a mini-batch of 3 sequences with variable-length,
each containing 2, 3, 2 time-steps, the lod of which is [0, 2, 5, 7],
then softmax will be computed among X[0:2, :], X[2:5, :], X[5:7, :]
and N turns out to be 7.

)DOC");
  }
};

class SequenceSoftmaxGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE(ctx->HasInput("Out"),
                   "Input(Out) of SequenceSoftmaxGradOp should not be null.");
    PADDLE_ENFORCE(
        ctx->HasInput(framework::GradVarName("Out")),
        "Input(Out@GRAD) of SequenceSoftmaxGradOp should not be null.");
    PADDLE_ENFORCE(ctx->HasInput("X"),
                   "Input(X) of SequenceSoftmaxOp should not be null.");
    PADDLE_ENFORCE(ctx->HasOutput(framework::GradVarName("X")),
                   "Output(X@GRAD) of SequenceSoftmaxOp should not be null.");

    PADDLE_ENFORCE_EQ(
        ctx->GetInputDim("Out"),
        ctx->GetInputDim(framework::GradVarName("Out")),
        "Input(Out) and Input(Out@GRAD) of SequenceSoftmaxGradOp should be of "
        "the same shape.");

    ctx->SetOutputDim(framework::GradVarName("X"), ctx->GetInputDim("X"));
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    // choose cudnn kernel if the runtime supported.
    bool use_cudnn = ctx.Attr<bool>("use_cudnn");
    bool runtime_cudnn_support = false;
#ifdef PADDLE_WITH_CUDA
    if (platform::is_gpu_place(ctx.GetPlace())) {
      auto& dev_ctx =
          ctx.template device_context<platform::CUDADeviceContext>();
      runtime_cudnn_support = dev_ctx.cudnn_handle() != nullptr ? true : false;
    }
#endif
    framework::LibraryType library_ = framework::LibraryType::kPlain;
    if (use_cudnn && runtime_cudnn_support) {
      library_ = framework::LibraryType::kCUDNN;
    }
    std::string data_format = ctx.Attr<std::string>("data_format");
    return framework::OpKernelType(
        ctx.Input<Tensor>("Out")->type(), ctx.GetPlace(),
        framework::StringToDataLayout(data_format), library_);
  }
};

DECLARE_NO_NEED_BUFFER_VARS_INFERENCE(
    SequenceSoftmaxGradOpNoNeedBufferVarsInferer, "X");

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(sequence_softmax, ops::SequenceSoftmaxOp,
                  ops::SequenceSoftmaxOpMaker,
                  paddle::framework::DefaultGradOpDescMaker<true>);
REGISTER_OPERATOR(sequence_softmax_grad, ops::SequenceSoftmaxGradOp,
                  ops::SequenceSoftmaxGradOpNoNeedBufferVarsInferer);
REGISTER_OP_CPU_KERNEL(
    sequence_softmax,
    ops::SequenceSoftmaxKernel<paddle::platform::CPUDeviceContext, float>,
    ops::SequenceSoftmaxKernel<paddle::platform::CPUDeviceContext, double>);
REGISTER_OP_CPU_KERNEL(
    sequence_softmax_grad,
    ops::SequenceSoftmaxGradKernel<paddle::platform::CPUDeviceContext, float>,
    ops::SequenceSoftmaxGradKernel<paddle::platform::CPUDeviceContext, double>);
<|endoftext|>


<commit_before>#include "overlay.h"
#include <iostream>
#include <QInputDialog>

/**
 * @brief overlay::overlay
 */
overlay::overlay() {
}

/**
 * @brief overlay::draw_overlay
 * Draws an overlay on top of the specified QImage.
 * @param img QImage to draw on
 */
void overlay::draw_overlay(QImage &img, int frame_nr) {
    if (show_overlay) {
        foreach (shape* s, overlays[frame_nr]) {
            s->draw(img);
        }
    }
}

/**
 * @brief overlay::toggle_overlay
 * Toggles the showing of the overlay, and if video is paused updates
 * the frame in the GUI to show with/without overlay
 */
void overlay::toggle_overlay() {
    show_overlay = !show_overlay;
}

/**
 * @brief overlay::is_showing_overlay
 * @return Returns true if the overlay is currently on
 */
bool overlay::is_showing_overlay() {
    return show_overlay;
}

/**
 * @brief overlay::set_showing_overlay
 * @param value
 */
void overlay::set_showing_overlay(bool value) {
    show_overlay = value;
}

/**
 * @brief overlay::set_tool
 * Sets the overlay tool's shape.
 * If the tool is the text-tool the user is prompted to wnter a text.
 * @param s
 */
void overlay::set_tool(SHAPES s) {
    current_shape = s;
    if (s == TEXT) {
        current_string = QInputDialog::getText(NULL, "Text chooser", "Enter a text:");
    }
}

/**
 * @brief overlay::set_colour
 * Sets the overlay tool's colour.
 * @param col
 */
void overlay::set_colour(QColor col) {
    current_colour = col;
}

/**
 * @brief overlay::get_colour
 * @return The currenty choosen colour.
 */
QColor overlay::get_colour() {
    return current_colour;
}

/**
 * @brief overlay::get_shape
 * @return The currently choosen shape
 */
SHAPES overlay::get_shape() {
    return current_shape;
}

/**
 * @brief overlay::mouse_pressed
 * Creates a drawing shape with the prechoosen colour
 * and shape, if the overlay is visible.
 * @param pos coordinates
 */
void overlay::mouse_pressed(QPoint pos, int frame_nr) {
    if (show_overlay) {
        switch (current_shape) {
            case RECTANGLE:
                overlays[frame_nr].append(new rectangle(current_colour, pos));
                break;
            case CIRCLE:
                overlays[frame_nr].append(new circle(current_colour, pos));
                break;
            case LINE:
                overlays[frame_nr].append(new line(current_colour, pos));
                break;
            case ARROW:
                overlays[frame_nr].append(new arrow(current_colour, pos));
                break;
            case PEN:
                overlays[frame_nr].append(new pen(current_colour, pos));
                break;
            case TEXT:
                overlays[frame_nr].append(new text(current_colour, pos, current_string));
                break;
            default:
                break;
        }
    }
}

/**
 * @brief overlay::mouse_pressed
 * Ends drawing on the overlay when the mouse is
 * released, if the overlay is visible.
 * @param pos coordinates
 */
void overlay::mouse_released(QPoint pos, int frame_nr) {
    update_drawing_position(pos, frame_nr);
}

/**
 * @brief overlay::mouse_moved
 * Updates drawing on the overlay when the mouse is
 * moved, if the overlay is visible.
 * @param pos coordinates
 */
void overlay::mouse_moved(QPoint pos, int frame_nr) {
    update_drawing_position(pos, frame_nr);
}

/**
 * @brief overlay::update_drawing_position
 * Updates the position of the end point of the shape currently being drawn
 * @param pos
 */
void overlay::update_drawing_position(QPoint pos, int frame_nr) {
    if (show_overlay) {
        // The last appended shape is the one we're currently drawing.
        overlays[frame_nr].last()->update_drawing_pos(pos);
    }
}

/**
 * @brief overlay::undo
 * Undo the drawings on the overlay, if the overlay is visible.
 */
void overlay::undo(int frame_nr) {
    if (show_overlay) {
        if (overlays[frame_nr].isEmpty()) {
            return;
        }
        overlays[frame_nr].takeLast(); // Requires a non-empty list.
    }
}

/**
 * @brief overlay::clear
 * Clear the drawings on the overlay, if the overlay is visible.
 */
void overlay::clear(int frame_nr) {
    if (show_overlay) {
        overlays[frame_nr].clear();
    }
}
<commit_msg>Edited erroneous comments.<commit_after>#include "overlay.h"
#include <iostream>
#include <QInputDialog>

/**
 * @brief overlay::overlay
 */
overlay::overlay() {
}

/**
 * @brief overlay::draw_overlay
 * Draws an overlay on top of the specified QImage.
 * @param img QImage to draw on
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::draw_overlay(QImage &img, int frame_nr) {
    if (show_overlay) {
        foreach (shape* s, overlays[frame_nr]) {
            s->draw(img);
        }
    }
}

/**
 * @brief overlay::toggle_overlay
 * Toggles the showing of the overlay, and if video is paused updates
 * the frame in the GUI to show with/without overlay
 */
void overlay::toggle_overlay() {
    show_overlay = !show_overlay;
}

/**
 * @brief overlay::is_showing_overlay
 * @return Returns true if the overlay is currently on
 */
bool overlay::is_showing_overlay() {
    return show_overlay;
}

/**
 * @brief overlay::set_showing_overlay
 * @param value
 */
void overlay::set_showing_overlay(bool value) {
    show_overlay = value;
}

/**
 * @brief overlay::set_tool
 * Sets the overlay tool's shape.
 * If the tool is the text-tool the user is prompted to wnter a text.
 * @param s
 */
void overlay::set_tool(SHAPES s) {
    current_shape = s;
    if (s == TEXT) {
        current_string = QInputDialog::getText(NULL, "Text chooser", "Enter a text:");
    }
}

/**
 * @brief overlay::set_colour
 * Sets the overlay tool's colour.
 * @param col
 */
void overlay::set_colour(QColor col) {
    current_colour = col;
}

/**
 * @brief overlay::get_colour
 * @return The currenty choosen colour.
 */
QColor overlay::get_colour() {
    return current_colour;
}

/**
 * @brief overlay::get_shape
 * @return The currently choosen shape
 */
SHAPES overlay::get_shape() {
    return current_shape;
}

/**
 * @brief overlay::mouse_pressed
 * Creates a drawing shape with the prechoosen colour
 * and shape, if the overlay is visible.
 * @param pos Mouse coordinates.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_pressed(QPoint pos, int frame_nr) {
    if (show_overlay) {
        switch (current_shape) {
            case RECTANGLE:
                overlays[frame_nr].append(new rectangle(current_colour, pos));
                break;
            case CIRCLE:
                overlays[frame_nr].append(new circle(current_colour, pos));
                break;
            case LINE:
                overlays[frame_nr].append(new line(current_colour, pos));
                break;
            case ARROW:
                overlays[frame_nr].append(new arrow(current_colour, pos));
                break;
            case PEN:
                overlays[frame_nr].append(new pen(current_colour, pos));
                break;
            case TEXT:
                overlays[frame_nr].append(new text(current_colour, pos, current_string));
                break;
            default:
                break;
        }
    }
}

/**
 * @brief overlay::mouse_released
 * Ends drawing on the overlay when the mouse is
 * released, if the overlay is visible.
 * @param pos Mouse coordinates.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_released(QPoint pos, int frame_nr) {
    update_drawing_position(pos, frame_nr);
}

/**
 * @brief overlay::mouse_moved
 * Updates drawing on the overlay when the mouse is
 * moved, if the overlay is visible.
 * @param pos Mouse coordinates.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::mouse_moved(QPoint pos, int frame_nr) {
    update_drawing_position(pos, frame_nr);
}

/**
 * @brief overlay::update_drawing_position
 * Updates the position of the end point of the shape currently being drawn
 * @param pos Mouse coordinates.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::update_drawing_position(QPoint pos, int frame_nr) {
    if (show_overlay) {
        // The last appended shape is the one we're currently drawing.
        overlays[frame_nr].last()->update_drawing_pos(pos);
    }
}

/**
 * @brief overlay::undo
 * Undo the drawings on the overlay, if the overlay is visible.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::undo(int frame_nr) {
    if (show_overlay) {
        if (overlays[frame_nr].isEmpty()) {
            return;
        }
        overlays[frame_nr].takeLast(); // Requires a non-empty list.
    }
}

/**
 * @brief overlay::clear
 * Clear the drawings on the overlay, if the overlay is visible.
 * @param frame_nr Number of the frame currently shown in the video.
 */
void overlay::clear(int frame_nr) {
    if (show_overlay) {
        overlays[frame_nr].clear();
    }
}
<|endoftext|>


<commit_before><commit_msg>Don't try to show filenames as sequence if there's only 1 file in the sequence.<commit_after><|endoftext|>


<commit_before><commit_msg>Don't care how long it takes in capture mode.<commit_after><|endoftext|>


<commit_before>//
// Some useful standalone functions for use with wxWindows.
//
// Copyright (c) 2002-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include <wx/image.h>
#include "wxString2.h"
#include "vtdata/FilePath.h"	// for dir_iter
#include "vtdata/vtLog.h"
#include "Helper.h"

wxBitmap *MakeColorBitmap(int xsize, int ysize, wxColour color)
{
	wxImage pImage(xsize, ysize);
	int i, j;
	for (i = 0; i < xsize; i++)
		for (j = 0; j < ysize; j++)
		{
			pImage.SetRGB(i, j, color.Red(), color.Green(), color.Blue());
		}

	wxBitmap *pBitmap = new wxBitmap(pImage);
	return pBitmap;
}

void FillWithColor(wxStaticBitmap *pStaticBitmap, const wxColour &color)
{
	wxBitmap bm = pStaticBitmap->GetBitmap();

	wxBitmap *pNewBitmap = MakeColorBitmap(bm.GetWidth(), bm.GetHeight(), color);
	pStaticBitmap->SetBitmap(*pNewBitmap);
	delete pNewBitmap;
}

void FillWithColor(wxBitmapButton *pBitmapButton, const wxColour &color)
{
	wxBitmap bm = pBitmapButton->GetBitmapLabel();

	wxBitmap *pNewBitmap = MakeColorBitmap(bm.GetWidth(), bm.GetHeight(), color);
	pBitmapButton->SetBitmapLabel(*pNewBitmap);
	delete pNewBitmap;
}

void FillWithColor(wxStaticBitmap *pStaticBitmap, const RGBi &color)
{
	FillWithColor(pStaticBitmap, wxColour(color.r, color.g, color.b));
}

void FillWithColor(wxBitmapButton *pBitmapButton, const RGBi &color)
{
	FillWithColor(pBitmapButton, wxColour(color.r, color.g, color.b));
}

/**
 * This function is used to find all files in a given directory,
 * and if they match a wildcard, add them to a combo box.
*/
int AddFilenamesToComboBox(wxComboBox *box, const char *directory,
	const char *wildcard, int omit_chars)
{
//  VTLOG(" AddFilenamesToComboBox '%s', '%s':", directory, wildcard);

	int entries = 0, matches = 0;

	wxString2 wildstr = wildcard;
	for (dir_iter it((const char *)directory); it != dir_iter(); ++it)
	{
		entries++;
		std::string name1 = it.filename();
		//	VTLOG("   entry: '%s'", name1.c_str());
		if (it.is_hidden() || it.is_directory())
			continue;

		wxString2 name = name1.c_str();
		if (name.Matches(wildstr))
		{
			if (omit_chars)
				box->Append(name.Left(name.Length()-omit_chars));
			else
				box->Append(name);
			matches++;
		}
	}
//  VTLOG(" %d entries, %d matches\n", entries, matches);
	return matches;
}

/**
 * This function is used to find all files in a given directory,
 * and if they match a wildcard, add them to a combo box.
*/
int AddFilenamesToChoice(wxChoice *choice, const char *directory,
	const char *wildcard, int omit_chars)
{
//  VTLOG(" AddFilenamesToComboBox '%s', '%s':", directory, wildcard);

	int entries = 0, matches = 0;

	wxString2 wildstr = wildcard;
	for (dir_iter it((const char *)directory); it != dir_iter(); ++it)
	{
		entries++;
		std::string name1 = it.filename();
		//	VTLOG("   entry: '%s'", name1.c_str());
		if (it.is_hidden() || it.is_directory())
			continue;

		wxString2 name = name1.c_str();
		if (name.Matches(wildstr))
		{
			if (omit_chars)
				choice->Append(name.Left(name.Length()-omit_chars));
			else
				choice->Append(name);
			matches++;
		}
	}
//  VTLOG(" %d entries, %d matches\n", entries, matches);
	return matches;
}

int AddFilenamesToStringArray(vtStringArray &array, const char *directory,
	const char *wildcard, int omit_chars)
{
	int matches = 0;
	for (dir_iter it(directory); it != dir_iter(); ++it)
	{
		if (it.is_hidden() || it.is_directory())
			continue;

		vtString name = it.filename().c_str();
		if (name.Matches(wildcard))
		{
			if (omit_chars)
				array.push_back(name.Left(name.GetLength()-omit_chars));
			else
				array.push_back(name);
			matches++;
		}
	}
	return matches;
}

///////////////////////////////////////////////////////////////////////

#if WIN32

#define BUFSIZE 80

//
// This code comes from Microsoft; it's the gnarly way of finding out
//  at runtime exactly what version of Windows we are running on.
//
bool LogWindowsVersion()
{
	OSVERSIONINFOEX osvi;
	BOOL bOsVersionInfoEx;

	// Try calling GetVersionEx using the OSVERSIONINFOEX structure.
	// If that fails, try using the OSVERSIONINFO structure.
	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

	if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
	{
		osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
		if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
			return false;
	}

	switch (osvi.dwPlatformId)
	{
		// Test for the Windows NT product family.
		case VER_PLATFORM_WIN32_NT:
			// Test for the specific product family.
			if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
				VTLOG("Windows Server 2003 family, ");

			if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
				VTLOG("Windows XP ");

			if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
				VTLOG("Windows 2000 ");

			if ( osvi.dwMajorVersion <= 4 )
				VTLOG("Windows NT ");

			// Test for specific product on Windows NT 4.0 SP6 and later.
			if( bOsVersionInfoEx )
			{
				// Test for the workstation type.
				if ( osvi.wProductType == VER_NT_WORKSTATION )
				{
					if( osvi.dwMajorVersion == 4 )
						VTLOG("Workstation 4.0 ");
					else if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
						VTLOG("Home Edition ");
					else
						VTLOG("Professional ");
				}

				// Test for the server type.
				else if ( osvi.wProductType == VER_NT_SERVER )
				{
					if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
					{
						if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
							VTLOG("Datacenter Edition ");
						else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
							VTLOG("Enterprise Edition ");
						else if ( osvi.wSuiteMask == VER_SUITE_BLADE )
							VTLOG("Web Edition ");
						else
							VTLOG("Standard Edition ");
					}

					else if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
					{
						if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
							VTLOG("Datacenter Server ");
						else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
							VTLOG("Advanced Server ");
						else
							VTLOG("Server ");
					}

					else  // Windows NT 4.0
					{
						if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
							VTLOG("Server 4.0, Enterprise Edition ");
						else
							VTLOG("Server 4.0 ");
					}
				}
			}
			else  // Test for specific product on Windows NT 4.0 SP5 and earlier
			{
				HKEY hKey;
				TCHAR szProductType[BUFSIZE];
				DWORD dwBufLen=BUFSIZE;
				LONG lRet;

				lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
					_T("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
					0, KEY_QUERY_VALUE, &hKey );
				if( lRet != ERROR_SUCCESS )
					return false;

				lRet = RegQueryValueEx( hKey, _T("ProductType"), NULL, NULL,
					(LPBYTE) szProductType, &dwBufLen);
				if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) )
					return false;

				RegCloseKey( hKey );

				if ( lstrcmpi( _T("WINNT"), szProductType) == 0 )
					VTLOG( "Workstation ");
				if ( lstrcmpi( _T("LANMANNT"), szProductType) == 0 )
					VTLOG( "Server ");
				if ( lstrcmpi( _T("SERVERNT"), szProductType) == 0 )
					VTLOG( "Advanced Server ");

				VTLOG( "%d.%d ", osvi.dwMajorVersion, osvi.dwMinorVersion );
			}

			// Display service pack (if any) and build number.
			if (osvi.dwMajorVersion == 4 &&
				 lstrcmpi( osvi.szCSDVersion, _T("Service Pack 6") ) == 0 )
			{
				HKEY hKey;
				LONG lRet;

				// Test for SP6 versus SP6a.
				lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
					_T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"),
					0, KEY_QUERY_VALUE, &hKey );
				if( lRet == ERROR_SUCCESS )
					VTLOG( "Service Pack 6a (Build %d)\n", osvi.dwBuildNumber & 0xFFFF );
				else // Windows NT 4.0 prior to SP6a
				{
					VTLOG( "%s (Build %d)\n",
						osvi.szCSDVersion,
						osvi.dwBuildNumber & 0xFFFF);
				}

				RegCloseKey( hKey );
			}
			else // Windows NT 3.51 and earlier or Windows 2000 and later
			{
				VTLOG( "%s (Build %d)\n",
					osvi.szCSDVersion,
					osvi.dwBuildNumber & 0xFFFF);
			}
			break;

		// Test for the Windows 95 product family.
		case VER_PLATFORM_WIN32_WINDOWS:
			if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
			{
				 VTLOG("Windows 95 ");
				 if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )
					 VTLOG("OSR2 ");
			}
			if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
			{
				 VTLOG("Windows 98 ");
				 if ( osvi.szCSDVersion[1] == 'A' )
					 VTLOG("SE ");
			}
			if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
			{
				 VTLOG("Windows Millennium Edition\n");
			}
			break;

		case VER_PLATFORM_WIN32s:
			VTLOG("Win32s\n");
			break;
	}
	return true;
}

#endif // WIN32

/////////////////////////////////

vtString FormatCoord(bool bGeo, double val, bool minsec)
{
	vtString str;
	if (bGeo)
	{
		if (minsec)
		{
			// show minutes and seconds
			double degree = val;
			double min = (degree - (int)degree) * 60.0f;
			double sec = (min - (int)min) * 60.0f;

			str.Format("%d %d' %.1f\"", (int)degree, (int)min, sec);
		}
		else
			str.Format("%3.6lf", val);	// decimal degrees
	}
	else
		str.Format("%.2lf", val);	// meters-based
	return str;
}

/////////////////////////////////

//
// Given a string name of a language like "de" or "German", return the
// enumerated language id, e.g. wxLANGUAGE_GERMAN.
//
enum wxLanguage GetLangFromName(const wxString &name)
{
	int lang;
	for (lang = wxLANGUAGE_ABKHAZIAN; lang < wxLANGUAGE_USER_DEFINED; lang++)
	{
		const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang);
		if (name.CmpNoCase(info->Description) == 0)
			return (enum wxLanguage) lang;
		if (name.Length() == 2)
		{
			wxString shortname = info->CanonicalName.Left(2);
			if (name.CmpNoCase(shortname) == 0)
				return (enum wxLanguage) lang;
		}
		else if (name.Length() == 5 && name[2] == '_')
		{
			if (name.CmpNoCase(info->CanonicalName) == 0)
				return (enum wxLanguage) lang;
		}
		else if (name.CmpNoCase(info->Description) == 0)
			return (enum wxLanguage) lang;
	}
	return wxLANGUAGE_UNKNOWN;
}

<commit_msg>chg to const wxBitmap &<commit_after>//
// Some useful standalone functions for use with wxWindows.
//
// Copyright (c) 2002-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include <wx/image.h>
#include "wxString2.h"
#include "vtdata/FilePath.h"	// for dir_iter
#include "vtdata/vtLog.h"
#include "Helper.h"

wxBitmap *MakeColorBitmap(int xsize, int ysize, wxColour color)
{
	wxImage pImage(xsize, ysize);
	int i, j;
	for (i = 0; i < xsize; i++)
		for (j = 0; j < ysize; j++)
		{
			pImage.SetRGB(i, j, color.Red(), color.Green(), color.Blue());
		}

	wxBitmap *pBitmap = new wxBitmap(pImage);
	return pBitmap;
}

void FillWithColor(wxStaticBitmap *pStaticBitmap, const wxColour &color)
{
	const wxBitmap &bm = pStaticBitmap->GetBitmap();

	wxBitmap *pNewBitmap = MakeColorBitmap(bm.GetWidth(), bm.GetHeight(), color);
	pStaticBitmap->SetBitmap(*pNewBitmap);
	delete pNewBitmap;
}

void FillWithColor(wxBitmapButton *pBitmapButton, const wxColour &color)
{
	const wxBitmap &bm = pBitmapButton->GetBitmapLabel();

	wxBitmap *pNewBitmap = MakeColorBitmap(bm.GetWidth(), bm.GetHeight(), color);
	pBitmapButton->SetBitmapLabel(*pNewBitmap);
	delete pNewBitmap;
}

void FillWithColor(wxStaticBitmap *pStaticBitmap, const RGBi &color)
{
	FillWithColor(pStaticBitmap, wxColour(color.r, color.g, color.b));
}

void FillWithColor(wxBitmapButton *pBitmapButton, const RGBi &color)
{
	FillWithColor(pBitmapButton, wxColour(color.r, color.g, color.b));
}

/**
 * This function is used to find all files in a given directory,
 * and if they match a wildcard, add them to a combo box.
*/
int AddFilenamesToComboBox(wxComboBox *box, const char *directory,
	const char *wildcard, int omit_chars)
{
//  VTLOG(" AddFilenamesToComboBox '%s', '%s':", directory, wildcard);

	int entries = 0, matches = 0;

	wxString2 wildstr = wildcard;
	for (dir_iter it((const char *)directory); it != dir_iter(); ++it)
	{
		entries++;
		std::string name1 = it.filename();
		//	VTLOG("   entry: '%s'", name1.c_str());
		if (it.is_hidden() || it.is_directory())
			continue;

		wxString2 name = name1.c_str();
		if (name.Matches(wildstr))
		{
			if (omit_chars)
				box->Append(name.Left(name.Length()-omit_chars));
			else
				box->Append(name);
			matches++;
		}
	}
//  VTLOG(" %d entries, %d matches\n", entries, matches);
	return matches;
}

/**
 * This function is used to find all files in a given directory,
 * and if they match a wildcard, add them to a combo box.
*/
int AddFilenamesToChoice(wxChoice *choice, const char *directory,
	const char *wildcard, int omit_chars)
{
//  VTLOG(" AddFilenamesToComboBox '%s', '%s':", directory, wildcard);

	int entries = 0, matches = 0;

	wxString2 wildstr = wildcard;
	for (dir_iter it((const char *)directory); it != dir_iter(); ++it)
	{
		entries++;
		std::string name1 = it.filename();
		//	VTLOG("   entry: '%s'", name1.c_str());
		if (it.is_hidden() || it.is_directory())
			continue;

		wxString2 name = name1.c_str();
		if (name.Matches(wildstr))
		{
			if (omit_chars)
				choice->Append(name.Left(name.Length()-omit_chars));
			else
				choice->Append(name);
			matches++;
		}
	}
//  VTLOG(" %d entries, %d matches\n", entries, matches);
	return matches;
}

int AddFilenamesToStringArray(vtStringArray &array, const char *directory,
	const char *wildcard, int omit_chars)
{
	int matches = 0;
	for (dir_iter it(directory); it != dir_iter(); ++it)
	{
		if (it.is_hidden() || it.is_directory())
			continue;

		vtString name = it.filename().c_str();
		if (name.Matches(wildcard))
		{
			if (omit_chars)
				array.push_back(name.Left(name.GetLength()-omit_chars));
			else
				array.push_back(name);
			matches++;
		}
	}
	return matches;
}

///////////////////////////////////////////////////////////////////////

#if WIN32

#define BUFSIZE 80

//
// This code comes from Microsoft; it's the gnarly way of finding out
//  at runtime exactly what version of Windows we are running on.
//
bool LogWindowsVersion()
{
	OSVERSIONINFOEX osvi;
	BOOL bOsVersionInfoEx;

	// Try calling GetVersionEx using the OSVERSIONINFOEX structure.
	// If that fails, try using the OSVERSIONINFO structure.
	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

	if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
	{
		osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
		if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
			return false;
	}

	switch (osvi.dwPlatformId)
	{
		// Test for the Windows NT product family.
		case VER_PLATFORM_WIN32_NT:
			// Test for the specific product family.
			if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
				VTLOG("Windows Server 2003 family, ");

			if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
				VTLOG("Windows XP ");

			if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
				VTLOG("Windows 2000 ");

			if ( osvi.dwMajorVersion <= 4 )
				VTLOG("Windows NT ");

			// Test for specific product on Windows NT 4.0 SP6 and later.
			if( bOsVersionInfoEx )
			{
				// Test for the workstation type.
				if ( osvi.wProductType == VER_NT_WORKSTATION )
				{
					if( osvi.dwMajorVersion == 4 )
						VTLOG("Workstation 4.0 ");
					else if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
						VTLOG("Home Edition ");
					else
						VTLOG("Professional ");
				}

				// Test for the server type.
				else if ( osvi.wProductType == VER_NT_SERVER )
				{
					if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
					{
						if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
							VTLOG("Datacenter Edition ");
						else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
							VTLOG("Enterprise Edition ");
						else if ( osvi.wSuiteMask == VER_SUITE_BLADE )
							VTLOG("Web Edition ");
						else
							VTLOG("Standard Edition ");
					}

					else if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
					{
						if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
							VTLOG("Datacenter Server ");
						else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
							VTLOG("Advanced Server ");
						else
							VTLOG("Server ");
					}

					else  // Windows NT 4.0
					{
						if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
							VTLOG("Server 4.0, Enterprise Edition ");
						else
							VTLOG("Server 4.0 ");
					}
				}
			}
			else  // Test for specific product on Windows NT 4.0 SP5 and earlier
			{
				HKEY hKey;
				TCHAR szProductType[BUFSIZE];
				DWORD dwBufLen=BUFSIZE;
				LONG lRet;

				lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
					_T("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
					0, KEY_QUERY_VALUE, &hKey );
				if( lRet != ERROR_SUCCESS )
					return false;

				lRet = RegQueryValueEx( hKey, _T("ProductType"), NULL, NULL,
					(LPBYTE) szProductType, &dwBufLen);
				if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) )
					return false;

				RegCloseKey( hKey );

				if ( lstrcmpi( _T("WINNT"), szProductType) == 0 )
					VTLOG( "Workstation ");
				if ( lstrcmpi( _T("LANMANNT"), szProductType) == 0 )
					VTLOG( "Server ");
				if ( lstrcmpi( _T("SERVERNT"), szProductType) == 0 )
					VTLOG( "Advanced Server ");

				VTLOG( "%d.%d ", osvi.dwMajorVersion, osvi.dwMinorVersion );
			}

			// Display service pack (if any) and build number.
			if (osvi.dwMajorVersion == 4 &&
				 lstrcmpi( osvi.szCSDVersion, _T("Service Pack 6") ) == 0 )
			{
				HKEY hKey;
				LONG lRet;

				// Test for SP6 versus SP6a.
				lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
					_T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"),
					0, KEY_QUERY_VALUE, &hKey );
				if( lRet == ERROR_SUCCESS )
					VTLOG( "Service Pack 6a (Build %d)\n", osvi.dwBuildNumber & 0xFFFF );
				else // Windows NT 4.0 prior to SP6a
				{
					VTLOG( "%s (Build %d)\n",
						osvi.szCSDVersion,
						osvi.dwBuildNumber & 0xFFFF);
				}

				RegCloseKey( hKey );
			}
			else // Windows NT 3.51 and earlier or Windows 2000 and later
			{
				VTLOG( "%s (Build %d)\n",
					osvi.szCSDVersion,
					osvi.dwBuildNumber & 0xFFFF);
			}
			break;

		// Test for the Windows 95 product family.
		case VER_PLATFORM_WIN32_WINDOWS:
			if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
			{
				 VTLOG("Windows 95 ");
				 if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )
					 VTLOG("OSR2 ");
			}
			if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
			{
				 VTLOG("Windows 98 ");
				 if ( osvi.szCSDVersion[1] == 'A' )
					 VTLOG("SE ");
			}
			if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
			{
				 VTLOG("Windows Millennium Edition\n");
			}
			break;

		case VER_PLATFORM_WIN32s:
			VTLOG("Win32s\n");
			break;
	}
	return true;
}

#endif // WIN32

/////////////////////////////////

vtString FormatCoord(bool bGeo, double val, bool minsec)
{
	vtString str;
	if (bGeo)
	{
		if (minsec)
		{
			// show minutes and seconds
			double degree = val;
			double min = (degree - (int)degree) * 60.0f;
			double sec = (min - (int)min) * 60.0f;

			str.Format("%d %d' %.1f\"", (int)degree, (int)min, sec);
		}
		else
			str.Format("%3.6lf", val);	// decimal degrees
	}
	else
		str.Format("%.2lf", val);	// meters-based
	return str;
}

/////////////////////////////////

//
// Given a string name of a language like "de" or "German", return the
// enumerated language id, e.g. wxLANGUAGE_GERMAN.
//
enum wxLanguage GetLangFromName(const wxString &name)
{
	int lang;
	for (lang = wxLANGUAGE_ABKHAZIAN; lang < wxLANGUAGE_USER_DEFINED; lang++)
	{
		const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang);
		if (name.CmpNoCase(info->Description) == 0)
			return (enum wxLanguage) lang;
		if (name.Length() == 2)
		{
			wxString shortname = info->CanonicalName.Left(2);
			if (name.CmpNoCase(shortname) == 0)
				return (enum wxLanguage) lang;
		}
		else if (name.Length() == 5 && name[2] == '_')
		{
			if (name.CmpNoCase(info->CanonicalName) == 0)
				return (enum wxLanguage) lang;
		}
		else if (name.CmpNoCase(info->Description) == 0)
			return (enum wxLanguage) lang;
	}
	return wxLANGUAGE_UNKNOWN;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * Licensed 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 "testsettings.hpp"
#ifdef TEST_DESTRUCTOR_THREAD_SAFETY

#include <realm.hpp>
#include <realm/util/features.h>
#include <memory>

#include "test.hpp"

using namespace realm;
using namespace realm::util;
using namespace realm::test_util;
using unit_test::TestContext;

// Tests thread safety of accessor chain manipulations related to LinkViews
TEST(ThreadSafety_LinkViewDestruction)
{
    std::vector<LinkViewRef> ptrs;
    Mutex mutex;
    Mutex destruct_mutex;
    test_util::ThreadWrapper thread;
    bool done = false;

    thread.start([&mutex, &destruct_mutex, &ptrs, &done] {
        while (true) {
            LockGuard lock(mutex);
            LockGuard lock1(destruct_mutex);
            ptrs.clear();
            if (done)
                break;
        }
    });

    for (int k = 0; k < 5; ++k) {
        auto group = std::make_shared<Group>();

        TableRef table = group->add_table("table");
        table->add_column(type_Int, "int");
        size_t col_link = table->add_column_link(type_LinkList, "links", *table);
        table->add_empty_row();
        table->add_empty_row();
        table->add_empty_row();
        {
            LinkViewRef links = table->get_linklist(col_link, 0);
            links->add(2);
            links->add(1);
            links->add(0);
        }
        table->add_empty_row();
        for (int i = 0; i < 10000; i++) {
            LinkViewRef links = table->get_linklist(col_link, 0);
            {
                LockGuard lock(mutex);
                ptrs.push_back(links);
            }
        }
        {
            LockGuard lock(destruct_mutex);
            group.reset();
        }
    }
    {
        LockGuard lock(destruct_mutex);
        done = true;
    }
    thread.join();
}

// Tests thread safety of accessor chain manipulations related to TableViews
// (implies queries and descriptors). This test revealed a bug in the management
// of Descriptors.
TEST(ThreadSafety_TableViewDestruction)
{
    std::vector<std::shared_ptr<TableView>> ptrs;
    Mutex mutex;
    Mutex destruct_mutex;
    test_util::ThreadWrapper thread;
    bool done = false;

    thread.start([&mutex, &destruct_mutex, &ptrs, &done] {
        while (true) {
            LockGuard lock(mutex);
            LockGuard lock1(destruct_mutex);
            ptrs.clear();
            if (done)
                break;
        }
    });

    for (int k = 0; k < 4; ++k) {
        auto group = std::make_shared<Group>();

        TableRef table = group->add_table("table");
        table->add_column(type_Int, "int");
        for (int i = 0; i < 1000; i++) {
            auto table_view = std::make_shared<TableView>(table->where().find_all());
            {
                LockGuard lock(mutex);
                ptrs.push_back(table_view);
            }
        }
        {
            LockGuard lock(destruct_mutex);
            group.reset();
        }
    }
    {
        LockGuard lock(destruct_mutex);
        done = true;
    }
    thread.join();
}

// Tests thread safety of accessor chain manipulations related to Rows
TEST(ThreadSafety_RowDestruction)
{
    std::vector<Row> ptrs;
    Mutex mutex;
    Mutex destruct_mutex;
    test_util::ThreadWrapper thread;
    bool done = false;

    thread.start([&mutex, &destruct_mutex, &ptrs, &done] {
        while (true) {
            LockGuard lock(mutex);
            LockGuard lock1(destruct_mutex);
            ptrs.clear();
            if (done)
                break;
        }
    });

    for (int k = 0; k < 100; ++k) {
        auto group = std::make_shared<Group>();

        TableRef table = group->add_table("table");
        table->add_column(type_Int, "int");
        table->add_empty_row();
        for (int i = 0; i < 10000; i++) {
            Row r = table->get(0);
            {
                LockGuard lock(mutex);
                ptrs.push_back(r);
            }
        }
        {
            LockGuard lock(destruct_mutex);
            group.reset();
        }
    }
    {
        LockGuard lock(destruct_mutex);
        done = true;
    }
    thread.join();
}

#endif
<commit_msg>Subtable's destructor is not thread safe<commit_after>/*************************************************************************
 *
 * Copyright 2016 Realm Inc.
 *
 * Licensed 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 "testsettings.hpp"
#ifdef TEST_DESTRUCTOR_THREAD_SAFETY

#include <realm.hpp>
#include <realm/util/features.h>
#include <memory>

#include "test.hpp"

using namespace realm;
using namespace realm::util;
using namespace realm::test_util;
using unit_test::TestContext;

// Tests thread safety of accessor chain manipulations related to LinkViews
TEST(ThreadSafety_LinkViewDestruction)
{
    std::vector<LinkViewRef> ptrs;
    Mutex mutex;
    Mutex destruct_mutex;
    test_util::ThreadWrapper thread;
    bool done = false;

    thread.start([&mutex, &destruct_mutex, &ptrs, &done] {
        while (true) {
            LockGuard lock(mutex);
            LockGuard lock1(destruct_mutex);
            ptrs.clear();
            if (done)
                break;
        }
    });

    for (int k = 0; k < 5; ++k) {
        auto group = std::make_shared<Group>();

        TableRef table = group->add_table("table");
        table->add_column(type_Int, "int");
        size_t col_link = table->add_column_link(type_LinkList, "links", *table);
        table->add_empty_row();
        table->add_empty_row();
        table->add_empty_row();
        {
            LinkViewRef links = table->get_linklist(col_link, 0);
            links->add(2);
            links->add(1);
            links->add(0);
        }
        table->add_empty_row();
        for (int i = 0; i < 10000; i++) {
            LinkViewRef links = table->get_linklist(col_link, 0);
            {
                LockGuard lock(mutex);
                ptrs.push_back(links);
            }
        }
        {
            LockGuard lock(destruct_mutex);
            group.reset();
        }
    }
    {
        LockGuard lock(destruct_mutex);
        done = true;
    }
    thread.join();
}

// Tests thread safety of accessor chain manipulations related to TableViews
// (implies queries and descriptors). This test revealed a bug in the management
// of Descriptors.
TEST(ThreadSafety_TableViewDestruction)
{
    std::vector<std::shared_ptr<TableView>> ptrs;
    Mutex mutex;
    Mutex destruct_mutex;
    test_util::ThreadWrapper thread;
    bool done = false;

    thread.start([&mutex, &destruct_mutex, &ptrs, &done] {
        while (true) {
            LockGuard lock(mutex);
            LockGuard lock1(destruct_mutex);
            ptrs.clear();
            if (done)
                break;
        }
    });

    for (int k = 0; k < 4; ++k) {
        auto group = std::make_shared<Group>();

        TableRef table = group->add_table("table");
        table->add_column(type_Int, "int");
        for (int i = 0; i < 1000; i++) {
            auto table_view = std::make_shared<TableView>(table->where().find_all());
            {
                LockGuard lock(mutex);
                ptrs.push_back(table_view);
            }
        }
        {
            LockGuard lock(destruct_mutex);
            group.reset();
        }
    }
    {
        LockGuard lock(destruct_mutex);
        done = true;
    }
    thread.join();
}

// Tests thread safety of accessor chain manipulations related to Rows
TEST(ThreadSafety_RowDestruction)
{
    std::vector<Row> ptrs;
    Mutex mutex;
    Mutex destruct_mutex;
    test_util::ThreadWrapper thread;
    bool done = false;

    thread.start([&mutex, &destruct_mutex, &ptrs, &done] {
        while (true) {
            LockGuard lock(mutex);
            LockGuard lock1(destruct_mutex);
            ptrs.clear();
            if (done)
                break;
        }
    });

    for (int k = 0; k < 100; ++k) {
        auto group = std::make_shared<Group>();

        TableRef table = group->add_table("table");
        table->add_column(type_Int, "int");
        table->add_empty_row();
        for (int i = 0; i < 10000; i++) {
            Row r = table->get(0);
            {
                LockGuard lock(mutex);
                ptrs.push_back(r);
            }
        }
        {
            LockGuard lock(destruct_mutex);
            group.reset();
        }
    }
    {
        LockGuard lock(destruct_mutex);
        done = true;
    }
    thread.join();
}

// Tests thread safety of subtable desctruction
ONLY(ThreadSafety_SubTableDestruction)
{
    std::vector<TableRef> ptrs;
    Mutex mutex;
    Mutex destruct_mutex;
    test_util::ThreadWrapper thread;
    bool done = false;

    thread.start([&mutex, &destruct_mutex, &ptrs, &done] {
        while (true) {
            LockGuard lock(mutex);
            LockGuard lock1(destruct_mutex);
            ptrs.clear();
            if (done)
                break;
        }
    });

    for (int k = 0; k < 100; ++k) {
        auto group = std::make_shared<Group>();

        TableRef table = group->add_table("table");
        DescriptorRef desc;
        auto subtable_col = table->add_column(type_Table, "list", &desc);
        desc->add_column(type_Int, "ARRAY_VALUE", nullptr, true);

        auto row_ndx = table->add_empty_row();
        for (int i = 0; i < 10000; i++) {
            TableRef subtable_ref = table->get_subtable(subtable_col, row_ndx);
            {
                LockGuard lock(mutex);
                ptrs.push_back(subtable_ref);
            }
        }
        {
            LockGuard lock(destruct_mutex);
            group.reset();
        }
    }
    {
        LockGuard lock(destruct_mutex);
        done = true;
    }
    thread.join();
}

#endif
<|endoftext|>


<commit_before>/**
 * Unit Tests for TicTacToeBoard
**/

#include <gtest/gtest.h>
#include "TicTacToeBoard.h"

class TicTacToeBoardTest : public ::testing::Test
{
	protected:
		TicTacToeBoardTest(){} //constructor runs before each test
		virtual ~TicTacToeBoardTest(){} //destructor cleans up after tests
		virtual void SetUp(){} //sets up before each test (after constructor)
		virtual void TearDown(){} //clean up after each test, (before destructor)
};

TEST(TicTacToeBoardTest, willToggle)
{
	TicTacToeBoard test;
	Piece asserted = O;
	Piece toggledTo = test.toggleTurn();
	EXPECT_TRUE(toggledTo == asserted);
}

TEST(TicTacToeBoardTest, willToggle2)
{
	TicTacToeBoard test;
	Piece asserted = O;
	Piece toggledTo = test.placePiece(0,0);
	toggledTo = test.placePiece(0,1);
	EXPECT_TRUE(toggledTo == asserted);
}

TEST(TicTacToeBoardTest, canPlace1)
{
	TicTacToeBoard test;
	Piece placed = test.placePiece(0,0);
	EXPECT_TRUE(placed == test.getPiece(0,0));
}

TEST(TicTacToeBoardTest, cannotPlaceColumn)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;
	Piece placed = test.placePiece(0,3);
	EXPECT_TRUE(placed == asserted);
}

TEST(TicTacToeBoardTest, cannotPlaceRow)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;
	Piece placed = test.placePiece(3,0);
	EXPECT_TRUE(placed == asserted);
}

TEST(TicTacToeBoardTest, cannotPlaceNegativeColumn)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;
	Piece placed = test.placePiece(0, -1);
	EXPECT_TRUE(placed == asserted);
}

TEST(TicTacToeBoardTest, cannotPlaceNegativeRow)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;
	Piece placed = test.placePiece(-1, 0);
	EXPECT_TRUE(placed == asserted);
}

// This test will fail due to the board not being filled even though X has won My 'bug'
TEST(TicTacToeBoardTest, seeWin)
{
	TicTacToeBoard test;
	Piece asserted = X;
	test.placePiece(0, 0); //place X
	test.placePiece(0, 1);
	test.placePiece(1, 0); //place X
	test.placePiece(2, 2);
	test.placePiece(2, 0); //place X
	EXPECT_TRUE(test.getWinner() == asserted);
}

/**
 * This tests for the fowards diagonal 0,0 to 2,2
**/
TEST(TicTacToeBoardTest, seeWin2)
{
	TicTacToeBoard test;
	Piece asserted = Blank;

	test.placePiece(0, 0); //X
	test.placePiece(0, 1); //O
	test.placePiece(0, 2); //X

	test.placePiece(1, 1); //O
	test.placePiece(1, 0); //X
	test.placePiece(1, 2); //O

	test.placePiece(2, 1); //X
	test.placePiece(2, 0); //O
	test.placePiece(2, 2); //X
	EXPECT_TRUE(test.getWinner() == asserted);
}

/**
 * This tests for the backwards diagonal 0,2 to 2,0
**/
TEST(TicTacToeBoardTest, seeWin3)
{
	TicTacToeBoard test;
	Piece asserted = O;

	test.placePiece(0, 0); //X
	test.placePiece(0, 2); //O
	test.placePiece(0, 1); //X

	test.placePiece(1, 1); //O
	test.placePiece(1, 0); //X
	test.placePiece(1, 2); //O

	test.placePiece(2, 1); //X
	test.placePiece(2, 0); //O
	test.placePiece(2, 2); //X
	EXPECT_TRUE(test.getWinner() == asserted);
}

/**
 * This tests for a straight up+down win
**/
TEST(TicTacToeBoardTest, seeWin4)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;

	EXPECT_TRUE(test.getWinner() == asserted);
}
<commit_msg>added test case for CAT games<commit_after>/**
 * Unit Tests for TicTacToeBoard
**/

#include <gtest/gtest.h>
#include "TicTacToeBoard.h"

class TicTacToeBoardTest : public ::testing::Test
{
	protected:
		TicTacToeBoardTest(){} //constructor runs before each test
		virtual ~TicTacToeBoardTest(){} //destructor cleans up after tests
		virtual void SetUp(){} //sets up before each test (after constructor)
		virtual void TearDown(){} //clean up after each test, (before destructor)
};

TEST(TicTacToeBoardTest, willToggle)
{
	TicTacToeBoard test;
	Piece asserted = O;
	Piece toggledTo = test.toggleTurn();
	EXPECT_TRUE(toggledTo == asserted);
}

TEST(TicTacToeBoardTest, willToggle2)
{
	TicTacToeBoard test;
	Piece asserted = O;
	Piece toggledTo = test.placePiece(0,0);
	toggledTo = test.placePiece(0,1);
	EXPECT_TRUE(toggledTo == asserted);
}

TEST(TicTacToeBoardTest, canPlace1)
{
	TicTacToeBoard test;
	Piece placed = test.placePiece(0,0);
	EXPECT_TRUE(placed == test.getPiece(0,0));
}

TEST(TicTacToeBoardTest, cannotPlaceColumn)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;
	Piece placed = test.placePiece(0,3);
	EXPECT_TRUE(placed == asserted);
}

TEST(TicTacToeBoardTest, cannotPlaceRow)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;
	Piece placed = test.placePiece(3,0);
	EXPECT_TRUE(placed == asserted);
}

TEST(TicTacToeBoardTest, cannotPlaceNegativeColumn)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;
	Piece placed = test.placePiece(0, -1);
	EXPECT_TRUE(placed == asserted);
}

TEST(TicTacToeBoardTest, cannotPlaceNegativeRow)
{
	TicTacToeBoard test;
	Piece asserted = Invalid;
	Piece placed = test.placePiece(-1, 0);
	EXPECT_TRUE(placed == asserted);
}

// BUG: This test will fail due to the board not being filled even though X has won
TEST(TicTacToeBoardTest, seeWin)
{
	TicTacToeBoard test;
	Piece asserted = X;
	test.placePiece(0, 0); //place X
	test.placePiece(0, 1);
	test.placePiece(1, 0); //place X
	test.placePiece(2, 2);
	test.placePiece(2, 0); //place X
	EXPECT_TRUE(test.getWinner() == asserted);
}

/**
 * This tests for the fowards diagonal 0,0 to 2,2
**/
TEST(TicTacToeBoardTest, seeWin2)
{
	TicTacToeBoard test;
	Piece asserted = Blank;

	test.placePiece(0, 0); //X
	test.placePiece(0, 1); //O
	test.placePiece(0, 2); //X

	test.placePiece(1, 1); //O
	test.placePiece(1, 0); //X
	test.placePiece(1, 2); //O

	test.placePiece(2, 1); //X
	test.placePiece(2, 0); //O
	test.placePiece(2, 2); //X
	EXPECT_TRUE(test.getWinner() == asserted);
}

/**
 * This tests for the backwards diagonal 0,2 to 2,0
**/
TEST(TicTacToeBoardTest, seeWin3)
{
	TicTacToeBoard test;
	Piece asserted = O;

	test.placePiece(0, 0); //X
	test.placePiece(0, 2); //O
	test.placePiece(0, 1); //X

	test.placePiece(1, 1); //O
	test.placePiece(1, 0); //X
	test.placePiece(1, 2); //O

	test.placePiece(2, 1); //X
	test.placePiece(2, 0); //O
	test.placePiece(2, 2); //X
	EXPECT_TRUE(test.getWinner() == asserted);
}

/**
 * This tests for a cat game
**/
TEST(TicTacToeBoardTest, seeWin4)
{
	TicTacToeBoard test;
	Piece asserted = Blank;
	test.placePiece(0, 0); //X
	test.placePiece(0, 1); //O
	test.placePiece(0, 2); //X

	test.placePiece(1, 0); //O
	test.placePiece(1, 2); //X
	test.placePiece(1, 1); //O

	test.placePiece(2, 1); //X
	test.placePiece(2, 2); //O
	test.placePiece(2, 0); //X
	EXPECT_TRUE(test.getWinner() == asserted);
}

TEST(TicTacToeBoardTest, placeMore)
{
	TicTacToeBoard test;
	Piece asserted = O;
	test.placePiece(0, 0); //X
	test.placePiece(0, 1); //O
	test.placePiece(0, 2); //X

	test.placePiece(1, 0); //O
	test.placePiece(1, 2); //X
	test.placePiece(1, 1); //O

	test.placePiece(2, 1); //X
	test.placePiece(2, 2); //O
	test.placePiece(2, 0); //X
	EXPECT_TRUE(test.placePiece(0, 0) == asserted);
}
<|endoftext|>