<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() + ";} "
                                "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);

    //Horizontal Layout
    //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

    horlayout->addSpacing(10);

    //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

    horlayout->addSpacing(10);

    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() + ";}");

    //End Horizontal Layout

    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(this);
    vertlayout->addWidget(userSettingsBox);
    userSettingsBox->setTitle("User Settings");

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

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

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

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

    horlayout->addSpacing(10);

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

    accentButton = new QPushButton(this);
    accentButton->setFont(buttonFont);
    accentButton->setStyleSheet("QPushButton{ background-color: " + p->value("Accent/LightAccent").toString() + ";""}");
    accentButton->setText("Set Light Accent");
    accentButton_2 = new QPushButton(this);
    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(this);
    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(this);
    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

    horlayout->addSpacing(10);

    QGroupBox* testSettingsBox = new QGroupBox(this);
    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() + ";}");

    //End Horizontal Layout

    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>// Time:  O(logn)
// Space: O(1)

class Solution {
public:
    double myPow(double x, int n) {
        double res = 1;
        long abs_n = abs(static_cast<long>(n));
        while (abs_n > 0) {
            if (abs_n & 1) {
                res *= x;
            }
            abs_n >>= 1;
            x *= x;
        }
        return n < 0 ?  1 / res : res;
    }
};
<commit_msg>Update powx-n.cpp<commit_after>// Time:  O(logn * nlogx * logx) = O(1)
// Space: O(nlogx) = O(1)

class Solution {
public:
    double myPow(double x, int n) {
        double res = 1;
        long abs_n = abs(static_cast<long>(n));
        while (abs_n > 0) {
            if (abs_n & 1) {
                res *= x;
            }
            abs_n >>= 1;
            x *= x;
        }
        return n < 0 ?  1 / res : res;
    }
};

// Time:  O(logn * nlogx * logx) = O(1)
// Space: O(nlogx) = O(1)
// Recursive solution.
class Solution2 {
public:
    double myPow(double x, int n) {
        if (n < 0 && n != -n) {
            return 1.0 / myPow(x, -n);
        }
        if (n == 0) {
            return 1;
        }
        double v = myPow(x, n / 2);
        if (n % 2 == 0) {
            return v * v;
        } else {
            return v * v * x;
        }
    }
};
<|endoftext|>


<commit_before>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

#include <cstdlib>
#include <qp_http_parse.h>

using namespace std;

#define  MQ_HTTP_RESPON_200_HTML  \
""\
""\
"<titile>MQ_Monitor</titile>"\
""\
""\
"
Method : %s
"\
"
URL : %s
"\
""\
"\0"

#define  MQ_HTTP_RESPON_400_HTML \
""\
""\
"<titile>MQ_Monitor</titile>"\
""\
""\
"
400 Not Found... T_T
"\
""\
"\0"

/*
 *
 */
int main(int argc, char** argv) {

    /*******************************************************
     * 50-72 行为demo创建监听套接字,用来接受网络连接.
     */
    int skt = socket(AF_INET, SOCK_STREAM, NULL);

    if (0 > skt) {
        return -1;
    }
    int set = 1;

    setsockopt(skt, SOL_SOCKET, SO_REUSEADDR,
        (const void *)&set, sizeof(set));

    struct sockaddr_in  addr;
    socklen_t           len = sizeof(addr);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8090);

    if (0 > bind(skt, (struct sockaddr*)&addr, len)) {
        return -1;
    }

    if (0 > listen(skt, 128)) {
        return -1;
    }
    /*******************************************************/

    int client = -1;
    /* 创建接受缓冲, 长度为 4k */
    char  readbuf[4096];
    /* 创建 http parser 对象 */
    qp_http_parse  parser;

    /* 接受连接 */
    while (0 < (client = accept(skt, NULL, NULL))) {
        /* recv_size 用来保存接受到的数据的字节数 */
        ssize_t recv_size = -1;

        /* 连续接收数据 */
        while (0 < (recv_size = read(client, readbuf, 4096))) {

            /* 调用parse的request_parse方法解析收到的请求数据, 这里每接受一点数据就
             * 解析一点,直到接受完整的请求后,解析也就完了.
             */
            switch (parser.request_parse(readbuf, recv_size)) {

                /* 如果 parser.request_parse 返回 QP_PARSER_SUCCESS 表示解析完成 */
                case QP_PARSER_SUCCESS: {
                    /* 解析成功后就可以使用解析出来的字段了,
                     * 可以调用 parser.respon_set_xxx
                     * 设置响应数据的各个字段的内容了. */

                    /* parser.responce_set_code 设置 HTTP 响应的 响应码,
                     * 如 200 OK ,400 BAD REQUEST ,500 INTERNAL ERROR 等,
                     * 这里这个函数的参数接受:
                     *    MQ_HTTP_RESPON_200_STAT
                     *    MQ_HTTP_RESPON_400_STAT
                     *    MQ_HTTP_RESPON_500_STAT   */
                    parser.responce_set_code(QP_HTTP_RESPON_200_STAT);

                    /* parser.responce_set_connection 设置 HTTP 响应的connection
                     * 字段,即 "connection: close" 或 "connection:keep-alive",
                     * 这里这个函数的参数接受:
                     *    QP_HTTP_RESPON_CLOSE 表示 "connection: close"
                     *    MQ_HTTP_RESPON_KEEPALIVE 表示 "connection:keep-alive"
                     *
                     * 一般设置 MQ_HTTP_RESPON_CLOSE 就好
                     */
                    parser.responce_set_connection(QP_HTTP_RESPON_CLOSE);

                    /* 这里设置响应的 Body,这个 Body中显示请求中的方法, 如 GET, POST等,
                     * 以及请求的URL.
                     *
                     *  parser.request_get_parsed_request()->method 获取请求的
                     * 方法, 返回const char* 型
                     *
                     * parser.request_get_parsed_request()->URL 获取请求的URL,
                     * 返回 const char* 型
                     *
                     * 其他可用的字段有:
                     * parser.request_get_parsed_request().content,表示 POST 或
                     * PUT 方法携带的数据体, 返回 const char*型
                     *
                     * parser.request_get_parsed_request().content_len, 表示
                     * 携带的数据体的长度, 返回 size_t 型
                     */
                    sprintf(readbuf, MQ_HTTP_RESPON_200_HTML,
                        parser.request_get_parsed_request()->method,
                        parser.request_get_parsed_request()->URL);

                    /* 设置响应的 Body 为刚才的readbuf */
                    parser.responce_set_body(readbuf);

                    /* struct iovec 为 linux 下的数据类型,保存的是分块的数据 */
                    struct iovec  *writebuf;

                    /* parser.responce_get_frame将组好的响应数据赋值给 writebuf,
                     * 并返回相应中的字段数量 */
                    size_t size = parser.responce_get_frame(&(writebuf));

                    /* writev 也是linux下的函数, 用来将分块数据一起发送出去,这里将
                     * 上一步获取的响应的分快数据发送出去. */
                    writev(client, writebuf, size);
                    goto next;

                } break;

                /* 如果 parser.request_parse 返回 QP_PARSER_ERROR 表示解析出错 */
                case QP_PARSER_ERROR: {

                } break;

                /* 如果返回 parser.request_parse 其他值,如 QP_PARSER_PARSING 就表示
                 * 当前收到的数据解析完了,但是请求不完整,需要等待身下的数据 */
                default: break;
            }
            /* 进行下次数据读取 */
        }

        next:
        /* 接收到的数据小于0 说明连接关闭或出错,则关闭连接 */
        close(client);
    }

    return 0;
}

<commit_msg>remove unfinished example.<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
 */

#include "common.h"
#include "bgfx_utils.h"
#include "imgui/imgui.h"

namespace
{

struct PosColorVertex
{
	float m_x;
	float m_y;
	float m_z;
	uint32_t m_abgr;

	static void init()
	{
		ms_decl
			.begin()
			.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
			.add(bgfx::Attrib::Color0,   4, bgfx::AttribType::Uint8, true)
			.end();
	};

	static bgfx::VertexDecl ms_decl;
};

bgfx::VertexDecl PosColorVertex::ms_decl;

static PosColorVertex s_cubeVertices[] =
{
	{-1.0f,  1.0f,  1.0f, 0xff000000 },
	{ 1.0f,  1.0f,  1.0f, 0xff0000ff },
	{-1.0f, -1.0f,  1.0f, 0xff00ff00 },
	{ 1.0f, -1.0f,  1.0f, 0xff00ffff },
	{-1.0f,  1.0f, -1.0f, 0xffff0000 },
	{ 1.0f,  1.0f, -1.0f, 0xffff00ff },
	{-1.0f, -1.0f, -1.0f, 0xffffff00 },
	{ 1.0f, -1.0f, -1.0f, 0xffffffff },
};

static const uint16_t s_cubeTriList[] =
{
	0, 1, 2, // 0
	1, 3, 2,
	4, 6, 5, // 2
	5, 6, 7,
	0, 2, 4, // 4
	4, 2, 6,
	1, 5, 3, // 6
	5, 7, 3,
	0, 4, 1, // 8
	4, 5, 1,
	2, 3, 6, // 10
	6, 3, 7,
};

static const uint16_t s_cubeTriStrip[] =
{
	0, 1, 2,
	3,
	7,
	1,
	5,
	0,
	4,
	2,
	6,
	7,
	4,
	5,
};

class ExampleCubes : public entry::AppI
{
public:
	ExampleCubes(const char* _name, const char* _description)
		: entry::AppI(_name, _description)
		, m_r(true)
		, m_g(true)
		, m_b(true)
		, m_a(true)
	{
	}

	void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
	{
		BX_UNUSED(s_cubeTriList, s_cubeTriStrip);

		Args args(_argc, _argv);

		m_width  = _width;
		m_height = _height;
		m_debug  = BGFX_DEBUG_NONE;
		m_reset  = BGFX_RESET_VSYNC;

		bgfx::Init init;
		init.type     = args.m_type;
		init.vendorId = args.m_pciId;
		init.resolution.width  = m_width;
		init.resolution.height = m_height;
		init.resolution.reset  = m_reset;
		bgfx::init(init);

		// Enable debug text.
		bgfx::setDebug(m_debug);

		// Set view 0 clear state.
		bgfx::setViewClear(0
				, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
				, 0x303030ff
				, 1.0f
				, 0
				);

		// Create vertex stream declaration.
		PosColorVertex::init();

		// Create static vertex buffer.
		m_vbh = bgfx::createVertexBuffer(
				// Static data can be passed with bgfx::makeRef
				bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) )
				, PosColorVertex::ms_decl
				);

		// Create static index buffer.
		m_ibh = bgfx::createIndexBuffer(
				// Static data can be passed with bgfx::makeRef
				bgfx::makeRef(s_cubeTriStrip, sizeof(s_cubeTriStrip) )
				);

		// Create program from shaders.
		m_program = loadProgram("vs_cubes", "fs_cubes");

		m_timeOffset = bx::getHPCounter();

		imguiCreate();
	}

	virtual int shutdown() override
	{
		imguiDestroy();

		// Cleanup.
		bgfx::destroy(m_ibh);
		bgfx::destroy(m_vbh);
		bgfx::destroy(m_program);

		// Shutdown bgfx.
		bgfx::shutdown();

		return 0;
	}

	bool update() override
	{
		if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
		{
			imguiBeginFrame(m_mouseState.m_mx
				,  m_mouseState.m_my
				, (m_mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT   : 0)
				| (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT  : 0)
				| (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
				,  m_mouseState.m_mz
				, uint16_t(m_width)
				, uint16_t(m_height)
				);

			showExampleDialog(this);

			ImGui::SetNextWindowPos(
				  ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
				, ImGuiCond_FirstUseEver
				);
			ImGui::SetNextWindowSize(
				  ImVec2(m_width / 5.0f, m_height / 4.0f)
				, ImGuiCond_FirstUseEver
				);
			ImGui::Begin("Settings"
				, NULL
				, 0
				);

			ImGui::Checkbox("Write R", &m_r);
			ImGui::Checkbox("Write G", &m_g);
			ImGui::Checkbox("Write B", &m_b);
			ImGui::Checkbox("Write A", &m_a);

			ImGui::End();

			imguiEndFrame();

			float time = (float)( (bx::getHPCounter()-m_timeOffset)/double(bx::getHPFrequency() ) );

			float at[3]  = { 0.0f, 0.0f,   0.0f };
			float eye[3] = { 0.0f, 0.0f, -35.0f };

			// Set view and projection matrix for view 0.
			const bgfx::HMD* hmd = bgfx::getHMD();
			if (NULL != hmd && 0 != (hmd->flags & BGFX_HMD_RENDERING) )
			{
				float view[16];
				bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye);
				bgfx::setViewTransform(0, view, hmd->eye[0].projection, BGFX_VIEW_STEREO, hmd->eye[1].projection);

				// Set view 0 default viewport.
				//
				// Use HMD's width/height since HMD's internal frame buffer size
				// might be much larger than window size.
				bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height);
			}
			else
			{
				float view[16];
				bx::mtxLookAt(view, eye, at);

				float proj[16];
				bx::mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
				bgfx::setViewTransform(0, view, proj);

				// Set view 0 default viewport.
				bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
			}

			// This dummy draw call is here to make sure that view 0 is cleared
			// if no other draw calls are submitted to view 0.
			bgfx::touch(0);

			// Submit 11x11 cubes.
			for (uint32_t yy = 0; yy < 11; ++yy)
			{
				for (uint32_t xx = 0; xx < 11; ++xx)
				{
					float mtx[16];
					bx::mtxRotateXY(mtx, time + xx*0.21f, time + yy*0.37f);
					mtx[12] = -15.0f + float(xx)*3.0f;
					mtx[13] = -15.0f + float(yy)*3.0f;
					mtx[14] = 0.0f;

					// Set model matrix for rendering.
					bgfx::setTransform(mtx);

					// Set vertex and index buffer.
					bgfx::setVertexBuffer(0, m_vbh);
					bgfx::setIndexBuffer(m_ibh);

					// Set render states.
					bgfx::setState(0
						| (m_r	? BGFX_STATE_WRITE_R : 0)
						| (m_g	? BGFX_STATE_WRITE_G : 0)
						| (m_b	? BGFX_STATE_WRITE_B : 0)
						| (m_a ? BGFX_STATE_WRITE_A : 0)
						| BGFX_STATE_WRITE_Z
						| BGFX_STATE_DEPTH_TEST_LESS
						| BGFX_STATE_CULL_CW
						| BGFX_STATE_MSAA
						| BGFX_STATE_PT_TRISTRIP
						);

					// Submit primitive for rendering to view 0.
					bgfx::submit(0, m_program);
				}
			}

			// Advance to next frame. Rendering thread will be kicked to
			// process submitted rendering primitives.
			bgfx::frame();

			return true;
		}

		return false;
	}

	entry::MouseState m_mouseState;

	uint32_t m_width;
	uint32_t m_height;
	uint32_t m_debug;
	uint32_t m_reset;
	bgfx::VertexBufferHandle m_vbh;
	bgfx::IndexBufferHandle m_ibh;
	bgfx::ProgramHandle m_program;
	int64_t m_timeOffset;

	bool m_r;
	bool m_g;
	bool m_b;
	bool m_a;
};

} // namespace

ENTRY_IMPLEMENT_MAIN(ExampleCubes, "01-cubes", "Rendering simple static mesh.");
<commit_msg>Cleanup.<commit_after>/*
 * Copyright 2011-2018 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
 */

#include "common.h"
#include "bgfx_utils.h"
#include "imgui/imgui.h"

namespace
{

struct PosColorVertex
{
	float m_x;
	float m_y;
	float m_z;
	uint32_t m_abgr;

	static void init()
	{
		ms_decl
			.begin()
			.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
			.add(bgfx::Attrib::Color0,   4, bgfx::AttribType::Uint8, true)
			.end();
	};

	static bgfx::VertexDecl ms_decl;
};

bgfx::VertexDecl PosColorVertex::ms_decl;

static PosColorVertex s_cubeVertices[] =
{
	{-1.0f,  1.0f,  1.0f, 0xff000000 },
	{ 1.0f,  1.0f,  1.0f, 0xff0000ff },
	{-1.0f, -1.0f,  1.0f, 0xff00ff00 },
	{ 1.0f, -1.0f,  1.0f, 0xff00ffff },
	{-1.0f,  1.0f, -1.0f, 0xffff0000 },
	{ 1.0f,  1.0f, -1.0f, 0xffff00ff },
	{-1.0f, -1.0f, -1.0f, 0xffffff00 },
	{ 1.0f, -1.0f, -1.0f, 0xffffffff },
};

static const uint16_t s_cubeTriList[] =
{
	0, 1, 2, // 0
	1, 3, 2,
	4, 6, 5, // 2
	5, 6, 7,
	0, 2, 4, // 4
	4, 2, 6,
	1, 5, 3, // 6
	5, 7, 3,
	0, 4, 1, // 8
	4, 5, 1,
	2, 3, 6, // 10
	6, 3, 7,
};

static const uint16_t s_cubeTriStrip[] =
{
	0, 1, 2,
	3,
	7,
	1,
	5,
	0,
	4,
	2,
	6,
	7,
	4,
	5,
};

class ExampleCubes : public entry::AppI
{
public:
	ExampleCubes(const char* _name, const char* _description)
		: entry::AppI(_name, _description)
		, m_r(true)
		, m_g(true)
		, m_b(true)
		, m_a(true)
	{
	}

	void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
	{
		BX_UNUSED(s_cubeTriList, s_cubeTriStrip);

		Args args(_argc, _argv);

		m_width  = _width;
		m_height = _height;
		m_debug  = BGFX_DEBUG_NONE;
		m_reset  = BGFX_RESET_VSYNC;

		bgfx::Init init;
		init.type     = args.m_type;
		init.vendorId = args.m_pciId;
		init.resolution.width  = m_width;
		init.resolution.height = m_height;
		init.resolution.reset  = m_reset;
		bgfx::init(init);

		// Enable debug text.
		bgfx::setDebug(m_debug);

		// Set view 0 clear state.
		bgfx::setViewClear(0
				, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
				, 0x303030ff
				, 1.0f
				, 0
				);

		// Create vertex stream declaration.
		PosColorVertex::init();

		// Create static vertex buffer.
		m_vbh = bgfx::createVertexBuffer(
				// Static data can be passed with bgfx::makeRef
				bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) )
				, PosColorVertex::ms_decl
				);

		// Create static index buffer.
		m_ibh = bgfx::createIndexBuffer(
				// Static data can be passed with bgfx::makeRef
				bgfx::makeRef(s_cubeTriStrip, sizeof(s_cubeTriStrip) )
				);

		// Create program from shaders.
		m_program = loadProgram("vs_cubes", "fs_cubes");

		m_timeOffset = bx::getHPCounter();

		imguiCreate();
	}

	virtual int shutdown() override
	{
		imguiDestroy();

		// Cleanup.
		bgfx::destroy(m_ibh);
		bgfx::destroy(m_vbh);
		bgfx::destroy(m_program);

		// Shutdown bgfx.
		bgfx::shutdown();

		return 0;
	}

	bool update() override
	{
		if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
		{
			imguiBeginFrame(m_mouseState.m_mx
				,  m_mouseState.m_my
				, (m_mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT   : 0)
				| (m_mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT  : 0)
				| (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
				,  m_mouseState.m_mz
				, uint16_t(m_width)
				, uint16_t(m_height)
				);

			showExampleDialog(this);

			ImGui::SetNextWindowPos(
				  ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
				, ImGuiCond_FirstUseEver
				);
			ImGui::SetNextWindowSize(
				  ImVec2(m_width / 5.0f, m_height / 4.0f)
				, ImGuiCond_FirstUseEver
				);
			ImGui::Begin("Settings"
				, NULL
				, 0
				);

			ImGui::Checkbox("Write R", &m_r);
			ImGui::Checkbox("Write G", &m_g);
			ImGui::Checkbox("Write B", &m_b);
			ImGui::Checkbox("Write A", &m_a);

			ImGui::End();

			imguiEndFrame();

			float time = (float)( (bx::getHPCounter()-m_timeOffset)/double(bx::getHPFrequency() ) );

			float at[3]  = { 0.0f, 0.0f,   0.0f };
			float eye[3] = { 0.0f, 0.0f, -35.0f };

			// Set view and projection matrix for view 0.
			const bgfx::HMD* hmd = bgfx::getHMD();
			if (NULL != hmd && 0 != (hmd->flags & BGFX_HMD_RENDERING) )
			{
				float view[16];
				bx::mtxQuatTranslationHMD(view, hmd->eye[0].rotation, eye);
				bgfx::setViewTransform(0, view, hmd->eye[0].projection, BGFX_VIEW_STEREO, hmd->eye[1].projection);

				// Set view 0 default viewport.
				//
				// Use HMD's width/height since HMD's internal frame buffer size
				// might be much larger than window size.
				bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height);
			}
			else
			{
				float view[16];
				bx::mtxLookAt(view, eye, at);

				float proj[16];
				bx::mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
				bgfx::setViewTransform(0, view, proj);

				// Set view 0 default viewport.
				bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height) );
			}

			// This dummy draw call is here to make sure that view 0 is cleared
			// if no other draw calls are submitted to view 0.
			bgfx::touch(0);

			// Submit 11x11 cubes.
			for (uint32_t yy = 0; yy < 11; ++yy)
			{
				for (uint32_t xx = 0; xx < 11; ++xx)
				{
					float mtx[16];
					bx::mtxRotateXY(mtx, time + xx*0.21f, time + yy*0.37f);
					mtx[12] = -15.0f + float(xx)*3.0f;
					mtx[13] = -15.0f + float(yy)*3.0f;
					mtx[14] = 0.0f;

					// Set model matrix for rendering.
					bgfx::setTransform(mtx);

					// Set vertex and index buffer.
					bgfx::setVertexBuffer(0, m_vbh);
					bgfx::setIndexBuffer(m_ibh);

					// Set render states.
					bgfx::setState(0
						| (m_r ? BGFX_STATE_WRITE_R : 0)
						| (m_g ? BGFX_STATE_WRITE_G : 0)
						| (m_b ? BGFX_STATE_WRITE_B : 0)
						| (m_a ? BGFX_STATE_WRITE_A : 0)
						| BGFX_STATE_WRITE_Z
						| BGFX_STATE_DEPTH_TEST_LESS
						| BGFX_STATE_CULL_CW
						| BGFX_STATE_MSAA
						| BGFX_STATE_PT_TRISTRIP
						);

					// Submit primitive for rendering to view 0.
					bgfx::submit(0, m_program);
				}
			}

			// Advance to next frame. Rendering thread will be kicked to
			// process submitted rendering primitives.
			bgfx::frame();

			return true;
		}

		return false;
	}

	entry::MouseState m_mouseState;

	uint32_t m_width;
	uint32_t m_height;
	uint32_t m_debug;
	uint32_t m_reset;
	bgfx::VertexBufferHandle m_vbh;
	bgfx::IndexBufferHandle m_ibh;
	bgfx::ProgramHandle m_program;
	int64_t m_timeOffset;

	bool m_r;
	bool m_g;
	bool m_b;
	bool m_a;
};

} // namespace

ENTRY_IMPLEMENT_MAIN(ExampleCubes, "01-cubes", "Rendering simple static mesh.");
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2009-2010  Sandro Santilli <strk@keybit.net>
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 ***********************************************************************
 *
 * Last port: operation/overlay/snap/LineStringSnapper.java r309 (JTS-1.11+)
 *
 **********************************************************************/

#include <geos/operation/overlay/snap/LineStringSnapper.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateList.h>
#include <geos/util/UniqueCoordinateArrayFilter.h>
#include <geos/geom/LineSegment.h>

#include <vector>
#include <memory>

#ifndef GEOS_DEBUG
#define GEOS_DEBUG 0
#endif

#if GEOS_DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif

//using namespace std;
using namespace geos::geom;

namespace geos {
namespace operation { // geos.operation
namespace overlay { // geos.operation.overlay
namespace snap { // geos.operation.overlay.snap

/*public*/
std::auto_ptr<Coordinate::Vect>
LineStringSnapper::snapTo(const geom::Coordinate::ConstVect& snapPts)
{
	geom::CoordinateList coordList(srcPts);

	snapVertices(coordList, snapPts);
	snapSegments(coordList, snapPts);

	return coordList.toCoordinateArray();
}

/*private*/
void
LineStringSnapper::snapVertices(geom::CoordinateList& srcCoords,
			const geom::Coordinate::ConstVect& snapPts)
{
	using geom::CoordinateList;

	geom::Coordinate::ConstVect::const_iterator not_found = snapPts.end();

	// try snapping vertices
	// if src is a ring then don't snap final vertex
	CoordinateList::iterator it = srcCoords.begin();
	CoordinateList::iterator end = srcCoords.end();
	CoordinateList::iterator last = end; --last;
  if ( isClosed ) --end;
	for ( ; it != end; ++it )
	{
		Coordinate& srcPt = *it;

#if GEOS_DEBUG
cerr << "Checking for a snap for source coordinate " << srcPt << endl;
#endif

		geom::Coordinate::ConstVect::const_iterator found = findSnapForVertex(srcPt, snapPts);
		if ( found == not_found )
		{	// no snaps found (or no need to snap)
#if GEOS_DEBUG
cerr << "No snap found" << endl;
#endif
			continue;
		}

		assert(*found);
		const Coordinate& snapPt = *(*found);

#if GEOS_DEBUG
cerr << "Found snap point " << snapPt << endl;
#endif

		// update src with snap pt
		*it = snapPt;

#if GEOS_DEBUG
cerr << "Source point became " << srcPt << endl;
#endif

		// keep final closing point in synch (rings only)
		if (it == srcCoords.begin() && isClosed)
		{
			*last = snapPt;
		}
	}
}

/*private*/
Coordinate::ConstVect::const_iterator
LineStringSnapper::findSnapForVertex(const Coordinate& pt,
			const Coordinate::ConstVect& snapPts)
{

	// TODO: use std::find_if
	Coordinate::ConstVect::const_iterator end=snapPts.end();
	for ( Coordinate::ConstVect::const_iterator
			it=snapPts.begin();
			it != end;
			++it)
	{
		assert(*it);
		const Coordinate& snapPt = *(*it);

#if GEOS_DEBUG
cerr << " misuring distance between snap point " << snapPt << " and source point " << pt << endl;
#endif

		// shouldn't we look for *all* segments to be snapped rather then a single one?
		if ( snapPt.equals2D(pt) )
		{
#if GEOS_DEBUG
cerr << " points are equal, returning not-found " << endl;
#endif
			return end;
			//continue;
		}

		double dist = snapPt.distance(pt);
		if ( dist < snapTolerance )
		{
#if GEOS_DEBUG
cerr << " points are within distance (" << dist << ") returning iterator to snap point" << endl;
#endif
			return it;
		}
	}

#if GEOS_DEBUG
cerr << " No snap point within distance, returning not-found" << endl;
#endif

	return end;
}

/*private*/
void
LineStringSnapper::snapSegments(geom::CoordinateList& srcCoords,
			const geom::Coordinate::ConstVect& snapPts)
{

#if GEOS_DEBUG
cerr << " Snapping segment from: " << srcCoords << endl;
#endif

	for ( Coordinate::ConstVect::const_iterator
			it=snapPts.begin(), end=snapPts.end();
			it != end;
			++it)
	{
		assert(*it);
		const Coordinate& snapPt = *(*it);

#if GEOS_DEBUG
cerr << "Checking for a segment to snap to snapPt " << snapPt << endl;
#endif

		// shouldn't we look for *all* segments to be snapped
		// rather then a single one?
		CoordinateList::iterator too_far = srcCoords.end(); --too_far;
		CoordinateList::iterator segpos =
			findSegmentToSnap(snapPt, srcCoords.begin(), too_far);
		if ( segpos == too_far)
		{
#if GEOS_DEBUG
cerr << " No segment to snap" << endl;
#endif
			continue;
		}
#if GEOS_DEBUG
cerr << " Segment to be snapped found, inserting point" << endl;
#endif
		// insert must happen one-past first point (before next point)
		++segpos;
		srcCoords.insert(segpos, snapPt);
	}

#if GEOS_DEBUG
cerr << " After segment snapping, srcCoors are: " << srcCoords << endl;
#endif

}

/*private*/
/* NOTE: this is called findSegmentIndexToSnap in JTS */
CoordinateList::iterator
LineStringSnapper::findSegmentToSnap(
			const Coordinate& snapPt,
			CoordinateList::iterator from,
			CoordinateList::iterator too_far)
{
	LineSegment seg;
	double minDist = snapTolerance+1; // make sure the first closer then
	                                  // snapTolerance is accepted
	CoordinateList::iterator match=too_far;

	// TODO: use std::find_if
	for ( ; from != too_far; ++from)
	{
		seg.p0 = *from;
		CoordinateList::iterator to = from;
		++to;
		seg.p1 = *to;

#if GEOS_DEBUG
cerr << " Checking segment " << seg << " for snapping against point " << snapPt << endl;
#endif

		if ( seg.p0.equals2D(snapPt) || seg.p1.equals2D(snapPt) )
		{

#if GEOS_DEBUG
cerr << " One of segment endpoints equal snap point, returning too_far" << endl;
#endif
			if (allowSnappingToSourceVertices) {
				continue;
			} else {
				return too_far;
			}
		}

		double dist = seg.distance(snapPt);
#if GEOS_DEBUG
cerr << " dist=" << dist << " minDist=" << minDist << " snapTolerance=" << snapTolerance << endl;
#endif
		if ( dist < minDist && dist < snapTolerance )
		{
#if GEOS_DEBUG
cerr << " Segment/snapPt distance within tolerance and closer then previous match (" << dist << ") " << endl;
#endif
			match = from;
			minDist = dist;
		}
	}

	return match;
}

} // namespace geos.operation.snap
} // namespace geos.operation.overlay
} // namespace geos.operation
} // namespace geos

<commit_msg>update dox<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2009-2010  Sandro Santilli <strk@keybit.net>
 * Copyright (C) 2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 ***********************************************************************
 *
 * Last port: operation/overlay/snap/LineStringSnapper.java r309 (JTS-1.11+)
 *
 **********************************************************************/

#include <geos/operation/overlay/snap/LineStringSnapper.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateList.h>
#include <geos/util/UniqueCoordinateArrayFilter.h>
#include <geos/geom/LineSegment.h>

#include <vector>
#include <memory>

#ifndef GEOS_DEBUG
#define GEOS_DEBUG 0
#endif

#if GEOS_DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif

//using namespace std;
using namespace geos::geom;

namespace geos {
namespace operation { // geos.operation
namespace overlay { // geos.operation.overlay
namespace snap { // geos.operation.overlay.snap

/*public*/
std::auto_ptr<Coordinate::Vect>
LineStringSnapper::snapTo(const geom::Coordinate::ConstVect& snapPts)
{
	geom::CoordinateList coordList(srcPts);

	snapVertices(coordList, snapPts);
	snapSegments(coordList, snapPts);

	return coordList.toCoordinateArray();
}

/*private*/
void
LineStringSnapper::snapVertices(geom::CoordinateList& srcCoords,
			const geom::Coordinate::ConstVect& snapPts)
{
	using geom::CoordinateList;

	geom::Coordinate::ConstVect::const_iterator not_found = snapPts.end();

	// try snapping vertices
	// if src is a ring then don't snap final vertex
	CoordinateList::iterator it = srcCoords.begin();
	CoordinateList::iterator end = srcCoords.end();
	CoordinateList::iterator last = end; --last;
  if ( isClosed ) --end;
	for ( ; it != end; ++it )
	{
		Coordinate& srcPt = *it;

#if GEOS_DEBUG
cerr << "Checking for a snap for source coordinate " << srcPt << endl;
#endif

		geom::Coordinate::ConstVect::const_iterator found = findSnapForVertex(srcPt, snapPts);
		if ( found == not_found )
		{	// no snaps found (or no need to snap)
#if GEOS_DEBUG
cerr << "No snap found" << endl;
#endif
			continue;
		}

		assert(*found);
		const Coordinate& snapPt = *(*found);

#if GEOS_DEBUG
cerr << "Found snap point " << snapPt << endl;
#endif

		// update src with snap pt
		*it = snapPt;

#if GEOS_DEBUG
cerr << "Source point became " << srcPt << endl;
#endif

		// keep final closing point in synch (rings only)
		if (it == srcCoords.begin() && isClosed)
		{
			*last = snapPt;
		}
	}
}

/*private*/
Coordinate::ConstVect::const_iterator
LineStringSnapper::findSnapForVertex(const Coordinate& pt,
			const Coordinate::ConstVect& snapPts)
{

	// TODO: use std::find_if
	Coordinate::ConstVect::const_iterator end=snapPts.end();
	for ( Coordinate::ConstVect::const_iterator
			it=snapPts.begin();
			it != end;
			++it)
	{
		assert(*it);
		const Coordinate& snapPt = *(*it);

#if GEOS_DEBUG
cerr << " misuring distance between snap point " << snapPt << " and source point " << pt << endl;
#endif

		// shouldn't we look for *all* segments to be snapped rather then a single one?
		if ( snapPt.equals2D(pt) )
		{
#if GEOS_DEBUG
cerr << " points are equal, returning not-found " << endl;
#endif
			return end;
			//continue;
		}

		double dist = snapPt.distance(pt);
		if ( dist < snapTolerance )
		{
#if GEOS_DEBUG
cerr << " points are within distance (" << dist << ") returning iterator to snap point" << endl;
#endif
			return it;
		}
	}

#if GEOS_DEBUG
cerr << " No snap point within distance, returning not-found" << endl;
#endif

	return end;
}

/*private*/
void
LineStringSnapper::snapSegments(geom::CoordinateList& srcCoords,
			const geom::Coordinate::ConstVect& snapPts)
{

#if GEOS_DEBUG
cerr << " Snapping segment from: " << srcCoords << endl;
#endif

	for ( Coordinate::ConstVect::const_iterator
			it=snapPts.begin(), end=snapPts.end();
			it != end;
			++it)
	{
		assert(*it);
		const Coordinate& snapPt = *(*it);

#if GEOS_DEBUG
cerr << "Checking for a segment to snap to snapPt " << snapPt << endl;
#endif

		// shouldn't we look for *all* segments to be snapped
		// rather then a single one?
		CoordinateList::iterator too_far = srcCoords.end(); --too_far;
		CoordinateList::iterator segpos =
			findSegmentToSnap(snapPt, srcCoords.begin(), too_far);
		if ( segpos == too_far)
		{
#if GEOS_DEBUG
cerr << " No segment to snap" << endl;
#endif
			continue;
		}
#if GEOS_DEBUG
cerr << " Segment to be snapped found, inserting point" << endl;
#endif
		// insert must happen one-past first point (before next point)
		++segpos;
		srcCoords.insert(segpos, snapPt);
	}

#if GEOS_DEBUG
cerr << " After segment snapping, srcCoors are: " << srcCoords << endl;
#endif

}

/*private*/
/* NOTE: this is called findSegmentIndexToSnap in JTS */
CoordinateList::iterator
LineStringSnapper::findSegmentToSnap(
			const Coordinate& snapPt,
			CoordinateList::iterator from,
			CoordinateList::iterator too_far)
{
	LineSegment seg;
	double minDist = snapTolerance+1; // make sure the first closer then
	                                  // snapTolerance is accepted
	CoordinateList::iterator match=too_far;

	// TODO: use std::find_if
	for ( ; from != too_far; ++from)
	{
		seg.p0 = *from;
		CoordinateList::iterator to = from;
		++to;
		seg.p1 = *to;

#if GEOS_DEBUG
cerr << " Checking segment " << seg << " for snapping against point " << snapPt << endl;
#endif

		/**                                                                              * Check if the snap pt is equal to one of
		 * the segment endpoints.
		 *
		 * If the snap pt is already in the src list,
		 * don't snap at all (unless allowSnappingToSourceVertices
		 * is set to true)
		 */
		if ( seg.p0.equals2D(snapPt) || seg.p1.equals2D(snapPt) )
		{

#if GEOS_DEBUG
cerr << " One of segment endpoints equal snap point, returning too_far" << endl;
#endif
			if (allowSnappingToSourceVertices) {
				continue;
			} else {
				return too_far;
			}
		}

		double dist = seg.distance(snapPt);
#if GEOS_DEBUG
cerr << " dist=" << dist << " minDist=" << minDist << " snapTolerance=" << snapTolerance << endl;
#endif
		if ( dist < minDist && dist < snapTolerance )
		{
#if GEOS_DEBUG
cerr << " Segment/snapPt distance within tolerance and closer then previous match (" << dist << ") " << endl;
#endif
			match = from;
			minDist = dist;
		}
	}

	return match;
}

} // namespace geos.operation.snap
} // namespace geos.operation.overlay
} // namespace geos.operation
} // namespace geos

<|endoftext|>


<commit_before>#include <iostream>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>

#include <apr.h>
#include "akumuli.h"
#include "storage_engine/blockstore.h"
#include "storage_engine/volume.h"
#include "storage_engine/nbtree.h"
#include "log_iface.h"

void test_logger(aku_LogLevel tag, const char* msg) {
    BOOST_MESSAGE(msg);
}

struct AkumuliInitializer {
    AkumuliInitializer() {
        apr_initialize();
        Akumuli::Logger::set_logger(&test_logger);
    }
};

AkumuliInitializer initializer;

using namespace Akumuli;
using namespace Akumuli::StorageEngine;

static const std::vector<u32> CAPACITIES = { 8, 8 };  // two 64KB volumes
static const std::vector<std::string> VOLPATH = { "volume0", "volume1" };
static const std::string METAPATH = "metavolume";

static void create_blockstore() {
    Volume::create_new(VOLPATH[0].c_str(), CAPACITIES[0]);
    Volume::create_new(VOLPATH[1].c_str(), CAPACITIES[1]);
    MetaVolume::create_new(METAPATH.c_str(), 2, CAPACITIES.data());
}

static std::shared_ptr<FixedSizeFileStorage> open_blockstore() {
    auto bstore = FixedSizeFileStorage::open(METAPATH, VOLPATH);
    return bstore;
}

static void delete_blockstore() {
    apr_pool_t* pool;
    apr_pool_create(&pool, nullptr);
    apr_file_remove(METAPATH.c_str(), pool);
    apr_file_remove(VOLPATH[0].c_str(), pool);
    apr_file_remove(VOLPATH[1].c_str(), pool);
    apr_pool_destroy(pool);
}

void test_nbtree_forward(const int N) {
    delete_blockstore();
    create_blockstore();

    auto bstore = open_blockstore();
    NBTree tree(42, bstore);

    for (int i = 0; i < N; i++) {
        tree.append(i, i*0.1);
    }

    NBTreeCursor cursor(tree, 0, N);
    aku_Timestamp curr = 0ull;
    bool first = true;
    int index = 0;
    while(!cursor.is_eof()) {
        for (size_t ix = 0; ix < cursor.size(); ix++) {
            aku_Timestamp ts;
            double value;
            aku_Status status;
            std::tie(status, ts, value) = cursor.at(ix);

            BOOST_REQUIRE(status == AKU_SUCCESS);

            if (first) {
                first = false;
                curr = ts;
            }

            if (curr != ts) {
                BOOST_FAIL("Invalid timestamp, expected: " << curr  <<
                           " actual " << ts << " index " << index);
            }

            BOOST_REQUIRE_EQUAL(curr*0.1, value);

            curr++;
            index++;
        }
        cursor.proceed();
    }
    BOOST_REQUIRE_EQUAL(curr, N);

    delete_blockstore();
}

BOOST_AUTO_TEST_CASE(Test_nbtree_forward_0) {
    test_nbtree_forward(11);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_forward_1) {
    test_nbtree_forward(117);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_forward_2) {
    test_nbtree_forward(11771);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_forward_3) {
    test_nbtree_forward(100000);
}

void test_nbtree_roots_collection(u32 N) {
    std::shared_ptr<BlockStore> bstore = BlockStoreBuilder::create_memstore();
    std::vector<LogicAddr> addrlist;  // should be empty at first
    auto collection = std::make_shared<NBTreeRootsCollection>(42, addrlist, bstore);
    for (u32 i = 0; i < N; i++) {
        collection->append(i, 0.5*i);
    }
    // Read data back
    std::vector<aku_Timestamp> ts(N, 0);
    std::vector<double> xs(N, 0);
    auto it = collection->search(0, N);
    aku_Status status;
    size_t sz;
    std::tie(status, sz) = it->read(ts.data(), xs.data(), N);

    BOOST_REQUIRE_EQUAL(sz, N);

    BOOST_REQUIRE_EQUAL(status, AKU_SUCCESS);

    for (u32 i = 0; i < N; i++) {
        if (ts[i] != i) {
            BOOST_FAIL("Invalid timestamp at " << i << ", actual: " << ts[i]);
        }
        if (xs[i] != 0.5*i) {
            BOOST_FAIL("Invalid value at " << i << ", expected: " << (0.5*i) << ", actual: " << xs[i]);
        }
    }
}

BOOST_AUTO_TEST_CASE(Test_nbtree_rc_append_1) {
    test_nbtree_roots_collection(100);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_rc_append_2) {
    test_nbtree_roots_collection(2000);
}
<commit_msg>New failed unit-test added<commit_after>#include <iostream>

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>

#include <apr.h>
#include "akumuli.h"
#include "storage_engine/blockstore.h"
#include "storage_engine/volume.h"
#include "storage_engine/nbtree.h"
#include "log_iface.h"

void test_logger(aku_LogLevel tag, const char* msg) {
    BOOST_MESSAGE(msg);
}

struct AkumuliInitializer {
    AkumuliInitializer() {
        apr_initialize();
        Akumuli::Logger::set_logger(&test_logger);
    }
};

AkumuliInitializer initializer;

using namespace Akumuli;
using namespace Akumuli::StorageEngine;

static const std::vector<u32> CAPACITIES = { 8, 8 };  // two 64KB volumes
static const std::vector<std::string> VOLPATH = { "volume0", "volume1" };
static const std::string METAPATH = "metavolume";

static void create_blockstore() {
    Volume::create_new(VOLPATH[0].c_str(), CAPACITIES[0]);
    Volume::create_new(VOLPATH[1].c_str(), CAPACITIES[1]);
    MetaVolume::create_new(METAPATH.c_str(), 2, CAPACITIES.data());
}

static std::shared_ptr<FixedSizeFileStorage> open_blockstore() {
    auto bstore = FixedSizeFileStorage::open(METAPATH, VOLPATH);
    return bstore;
}

static void delete_blockstore() {
    apr_pool_t* pool;
    apr_pool_create(&pool, nullptr);
    apr_file_remove(METAPATH.c_str(), pool);
    apr_file_remove(VOLPATH[0].c_str(), pool);
    apr_file_remove(VOLPATH[1].c_str(), pool);
    apr_pool_destroy(pool);
}

void test_nbtree_forward(const int N) {
    delete_blockstore();
    create_blockstore();

    auto bstore = open_blockstore();
    NBTree tree(42, bstore);

    for (int i = 0; i < N; i++) {
        tree.append(i, i*0.1);
    }

    NBTreeCursor cursor(tree, 0, N);
    aku_Timestamp curr = 0ull;
    bool first = true;
    int index = 0;
    while(!cursor.is_eof()) {
        for (size_t ix = 0; ix < cursor.size(); ix++) {
            aku_Timestamp ts;
            double value;
            aku_Status status;
            std::tie(status, ts, value) = cursor.at(ix);

            BOOST_REQUIRE(status == AKU_SUCCESS);

            if (first) {
                first = false;
                curr = ts;
            }

            if (curr != ts) {
                BOOST_FAIL("Invalid timestamp, expected: " << curr  <<
                           " actual " << ts << " index " << index);
            }

            BOOST_REQUIRE_EQUAL(curr*0.1, value);

            curr++;
            index++;
        }
        cursor.proceed();
    }
    BOOST_REQUIRE_EQUAL(curr, N);

    delete_blockstore();
}

BOOST_AUTO_TEST_CASE(Test_nbtree_forward_0) {
    test_nbtree_forward(11);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_forward_1) {
    test_nbtree_forward(117);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_forward_2) {
    test_nbtree_forward(11771);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_forward_3) {
    test_nbtree_forward(100000);
}

void test_nbtree_roots_collection(u32 N) {
    std::shared_ptr<BlockStore> bstore = BlockStoreBuilder::create_memstore();
    std::vector<LogicAddr> addrlist;  // should be empty at first
    auto collection = std::make_shared<NBTreeRootsCollection>(42, addrlist, bstore);
    for (u32 i = 0; i < N; i++) {
        collection->append(i, 0.5*i);
    }
    // Read data back
    std::vector<aku_Timestamp> ts(N, 0);
    std::vector<double> xs(N, 0);
    auto it = collection->search(0, N);
    aku_Status status;
    size_t sz;
    std::tie(status, sz) = it->read(ts.data(), xs.data(), N);

    BOOST_REQUIRE_EQUAL(sz, N);

    BOOST_REQUIRE_EQUAL(status, AKU_SUCCESS);

    for (u32 i = 0; i < N; i++) {
        if (ts[i] != i) {
            BOOST_FAIL("Invalid timestamp at " << i << ", actual: " << ts[i]);
        }
        if (xs[i] != 0.5*i) {
            BOOST_FAIL("Invalid value at " << i << ", expected: " << (0.5*i) << ", actual: " << xs[i]);
        }
    }
}

BOOST_AUTO_TEST_CASE(Test_nbtree_rc_append_1) {
    test_nbtree_roots_collection(100);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_rc_append_2) {
    test_nbtree_roots_collection(2000);
}

BOOST_AUTO_TEST_CASE(Test_nbtree_rc_append_3) {
    test_nbtree_roots_collection(200000);
}
<|endoftext|>


<commit_before>//==============================================================================
// Compiler engine class
//==============================================================================

#include "compilerengine.h"
#include "compilermath.h"

//==============================================================================

#include <QApplication>
#include <QDir>
#include <QTextStream>

//==============================================================================

#include "llvm/LLVMContext.h"

#ifdef Q_WS_WIN
    // To include llvm/Module.h results in some indirect warnings from MSVC, but
    // it's LLVM's task to address them not ours, so...

    #pragma warning(disable: 4146)
#endif

#include "llvm/Module.h"

#ifdef Q_WS_WIN
    #pragma warning(default: 4146)
#endif

#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

#include "clang/Basic/Diagnostic.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"

//==============================================================================

namespace OpenCOR {
namespace Compiler {

//==============================================================================

CompilerEngine::CompilerEngine() :
    mModule(0),
    mExecutionEngine(0),
    mError(QString())
{
}

//==============================================================================

CompilerEngine::~CompilerEngine()
{
    // Reset ourselves

    reset();
}

//==============================================================================

void CompilerEngine::reset(const bool &pResetError)
{
    // Delete some internal objects

    delete mExecutionEngine;
    // Note: we must NOT delete mModule, since it gets deleted when deleting
    //       mExecutionEngine...

    mModule = 0;
    mExecutionEngine = 0;

    if (pResetError)
        mError = QString();
}

//==============================================================================

QString CompilerEngine::error() const
{
    // Return the compiler engine's error

    return mError;
}

//==============================================================================

bool CompilerEngine::hasError() const
{
    // Return whether an error occurred

    return !mError.isEmpty();
}

//==============================================================================

llvm::sys::Path getExecutablePath(const char *pArg) {
    return llvm::sys::Path::GetMainExecutable(pArg,
                                              (void *) (intptr_t) getExecutablePath);
}

//==============================================================================

bool CompilerEngine::compileCode(const QString &pCode,
                                 const bool &pOutputErrors)
{
    // Reset our compiler engine

    reset();

    // Check whether we want to compute a definite integral

    if (pCode.contains("defint(func")) {
        mError = tr("definite integrals are not yet supported");

        return false;
    }

    // Retrieve the application file name and determine the name of the
    // temporary file which will contain our model code

    QByteArray appByteArray = qApp->applicationFilePath().toLatin1();
    const char *appFileName = appByteArray.constData();

    QByteArray tempFileByteArray = QString(QDir::tempPath()+QDir::separator()+QFileInfo(appFileName).baseName()+".c").toLatin1();
    const char *tempFileName = tempFileByteArray.constData();

    // Save the model code in our temporary file

    QFile tempFile(tempFileName);

    if (!tempFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        mError = tr("%1 could not be created").arg(tempFileName);

        tempFile.remove();

        return false;
    }

    QTextStream out(&tempFile);

    out << pCode;

    tempFile.close();

    // Get a driver to compile our function

    llvm::raw_ostream &outputStream = pOutputErrors?llvm::errs():llvm::nulls();

    clang::DiagnosticsEngine diagnosticsEngine(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new clang::DiagnosticIDs()),
                                               new clang::TextDiagnosticPrinter(outputStream,
                                                                                clang::DiagnosticOptions()));
    clang::driver::Driver driver(getExecutablePath(appFileName).str(),
                                 llvm::sys::getDefaultTargetTriple(),
                                 "a.out", true, diagnosticsEngine);

    // Get a compilation object to which we pass some arguments
    // Note: in gcc, the -O3 option comes with a warning: "Under some
    //       circumstances where these optimizations are not favorable, this
    //       option might actually make a program slower." This is the reason
    //       we use -O2 to build OpenCOR. In Clang, however, there is no such
    //       warning, hence we use -O3 to compile a model...

    llvm::SmallVector<const char *, 16> compilationArguments;

    compilationArguments.push_back(appFileName);
    compilationArguments.push_back("-fsyntax-only");
    compilationArguments.push_back("-O3");
    compilationArguments.push_back("-Werror");
    compilationArguments.push_back(tempFileName);

    llvm::OwningPtr<clang::driver::Compilation> compilation(driver.BuildCompilation(compilationArguments));

    if (!compilation) {
        // We couldn't get a compilation object, so...

        mError = tr("the compilation object could not be created");

        tempFile.remove();

        return false;
    }

    // The compilation object should have only one command, so if it doesn't
    // then something went wrong

    const clang::driver::JobList &jobList = compilation->getJobs();

    if (   (jobList.size() != 1)
        || !llvm::isa<clang::driver::Command>(*jobList.begin())) {
        mError = tr("the compilation object must contain only one command");

        tempFile.remove();

        return false;
    }

    // Retrieve the command job

    const clang::driver::Command *command = llvm::cast<clang::driver::Command>(*jobList.begin());
    QString commandName = command->getCreator().getName();

    if (commandName.compare("clang")) {
        mError = tr("a clang command was expected, but a %1 command was found instead").arg(commandName);

        tempFile.remove();

        return false;
    }

    // Create a compiler invocation using our command's arguments

    const clang::driver::ArgStringList &commandArguments = command->getArguments();
    llvm::OwningPtr<clang::CompilerInvocation> compilerInvocation(new clang::CompilerInvocation());

    clang::CompilerInvocation::CreateFromArgs(*compilerInvocation,
                                              const_cast<const char **>(commandArguments.data()),
                                              const_cast<const char **>(commandArguments.data())+commandArguments.size(),
                                              diagnosticsEngine);

    // Create a compiler instance to handle the actual work

    clang::CompilerInstance compilerInstance;

    compilerInstance.setInvocation(compilerInvocation.take());

    // Create the compiler instance's diagnostics engine

    compilerInstance.createDiagnostics(int(commandArguments.size()),
                                       const_cast<char **>(commandArguments.data()),
                                       new clang::TextDiagnosticPrinter(outputStream,
                                                                        compilerInstance.getDiagnosticOpts()));

    if (!compilerInstance.hasDiagnostics()) {
        mError = tr("the diagnostics engine could not be created");

        tempFile.remove();

        return false;
    }

    // Create an LLVM module

    static int counter = 0;

    mModule = new llvm::Module(qPrintable(QString("Module #%1").arg(QString::number(++counter))),
                               llvm::getGlobalContext());

    // Initialise the native target, so not only can we then create a JIT
    // execution engine, but more importantly its data layout will match that of
    // our target platform...

    llvm::InitializeNativeTarget();

    // Create a JIT execution engine

    mExecutionEngine = llvm::ExecutionEngine::createJIT(mModule);

    if (!mExecutionEngine) {
        mError = tr("the JIT execution engine could not be created");

        tempFile.remove();

        delete mModule;

        return false;
    }

    // Create and execute the frontend to generate the LLVM assembly code,
    // making sure that all added functions end up in the same module

    llvm::OwningPtr<clang::CodeGenAction> codeGenerationAction(new clang::EmitLLVMOnlyAction(&mModule->getContext()));

    codeGenerationAction->setLinkModule(mModule);

    if (!compilerInstance.ExecuteAction(*codeGenerationAction, outputStream)) {
        mError = tr("the model could not be compiled");

        tempFile.remove();

        reset(false);

        return false;
    }

    // The LLVM assembly code was generated, so we can update our module and
    // delete our temporary file

    mModule = codeGenerationAction->takeModule();

    tempFile.remove();

    // Everything went fine, so...

    return true;
}

//==============================================================================

void * CompilerEngine::getFunction(const QString &pFunctionName)
{
    // Return the requested function

    return mExecutionEngine?mExecutionEngine->getPointerToFunction(mModule->getFunction(qPrintable(pFunctionName))):0;
}

//==============================================================================

}   // namespace Compiler
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Improved our Compiler plugin.<commit_after>//==============================================================================
// Compiler engine class
//==============================================================================

#include "compilerengine.h"
#include "compilermath.h"

//==============================================================================

#include <QApplication>
#include <QDir>
#include <QTemporaryFile>
#include <QTextStream>

//==============================================================================

#include "llvm/LLVMContext.h"

#ifdef Q_WS_WIN
    // To include llvm/Module.h results in some indirect warnings from MSVC, but
    // it's LLVM's task to address them not ours, so...

    #pragma warning(disable: 4146)
#endif

#include "llvm/Module.h"

#ifdef Q_WS_WIN
    #pragma warning(default: 4146)
#endif

#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

#include "clang/Basic/Diagnostic.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"

//==============================================================================

namespace OpenCOR {
namespace Compiler {

//==============================================================================

CompilerEngine::CompilerEngine() :
    mModule(0),
    mExecutionEngine(0),
    mError(QString())
{
}

//==============================================================================

CompilerEngine::~CompilerEngine()
{
    // Reset ourselves

    reset();
}

//==============================================================================

void CompilerEngine::reset(const bool &pResetError)
{
    // Delete some internal objects

    delete mExecutionEngine;
    // Note: we must NOT delete mModule, since it gets deleted when deleting
    //       mExecutionEngine...

    mModule = 0;
    mExecutionEngine = 0;

    if (pResetError)
        mError = QString();
}

//==============================================================================

QString CompilerEngine::error() const
{
    // Return the compiler engine's error

    return mError;
}

//==============================================================================

bool CompilerEngine::hasError() const
{
    // Return whether an error occurred

    return !mError.isEmpty();
}

//==============================================================================

llvm::sys::Path getExecutablePath(const char *pArg) {
    return llvm::sys::Path::GetMainExecutable(pArg,
                                              (void *) (intptr_t) getExecutablePath);
}

//==============================================================================

bool CompilerEngine::compileCode(const QString &pCode,
                                 const bool &pOutputErrors)
{
    // Reset our compiler engine

    reset();

    // Check whether we want to compute a definite integral

    if (pCode.contains("defint(func")) {
        mError = tr("definite integrals are not yet supported");

        return false;
    }

    // Retrieve the application file name and determine the name of the
    // temporary file which will contain our model code
    // Note: the temporary file will automatically get deleted when going out of
    //       scope...

    QByteArray appByteArray = qApp->applicationFilePath().toLatin1();
    const char *appFileName = appByteArray.constData();

    QTemporaryFile tempFile(QDir::tempPath()+QDir::separator()+QFileInfo(appFileName).baseName()+"_XXXXXX.c");

    if (!tempFile.open()) {
        mError = tr("%1 could not be created").arg(tempFile.fileName());

        return false;
    }

    QByteArray tempFileByteArray = tempFile.fileName().toLatin1();
    const char *tempFileName = tempFileByteArray.constData();

    // Save the model code in our temporary file

    QTextStream out(&tempFile);

    out << pCode;

    tempFile.close();

    // Get a driver to compile our function

    llvm::raw_ostream &outputStream = pOutputErrors?llvm::errs():llvm::nulls();

    clang::DiagnosticsEngine diagnosticsEngine(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new clang::DiagnosticIDs()),
                                               new clang::TextDiagnosticPrinter(outputStream,
                                                                                clang::DiagnosticOptions()));
    clang::driver::Driver driver(getExecutablePath(appFileName).str(),
                                 llvm::sys::getDefaultTargetTriple(),
                                 "a.out", true, diagnosticsEngine);

    // Get a compilation object to which we pass some arguments
    // Note: in gcc, the -O3 option comes with a warning: "Under some
    //       circumstances where these optimizations are not favorable, this
    //       option might actually make a program slower." This is the reason
    //       we use -O2 to build OpenCOR. In Clang, however, there is no such
    //       warning, hence we use -O3 to compile a model...

    llvm::SmallVector<const char *, 16> compilationArguments;

    compilationArguments.push_back(appFileName);
    compilationArguments.push_back("-fsyntax-only");
    compilationArguments.push_back("-O3");
    compilationArguments.push_back("-Werror");
    compilationArguments.push_back(tempFileName);

    llvm::OwningPtr<clang::driver::Compilation> compilation(driver.BuildCompilation(compilationArguments));

    if (!compilation) {
        // We couldn't get a compilation object, so...

        mError = tr("the compilation object could not be created");

        return false;
    }

    // The compilation object should have only one command, so if it doesn't
    // then something went wrong

    const clang::driver::JobList &jobList = compilation->getJobs();

    if (   (jobList.size() != 1)
        || !llvm::isa<clang::driver::Command>(*jobList.begin())) {
        mError = tr("the compilation object must contain only one command");

        return false;
    }

    // Retrieve the command job

    const clang::driver::Command *command = llvm::cast<clang::driver::Command>(*jobList.begin());
    QString commandName = command->getCreator().getName();

    if (commandName.compare("clang")) {
        mError = tr("a clang command was expected, but a %1 command was found instead").arg(commandName);

        return false;
    }

    // Create a compiler invocation using our command's arguments

    const clang::driver::ArgStringList &commandArguments = command->getArguments();
    llvm::OwningPtr<clang::CompilerInvocation> compilerInvocation(new clang::CompilerInvocation());

    clang::CompilerInvocation::CreateFromArgs(*compilerInvocation,
                                              const_cast<const char **>(commandArguments.data()),
                                              const_cast<const char **>(commandArguments.data())+commandArguments.size(),
                                              diagnosticsEngine);

    // Create a compiler instance to handle the actual work

    clang::CompilerInstance compilerInstance;

    compilerInstance.setInvocation(compilerInvocation.take());

    // Create the compiler instance's diagnostics engine

    compilerInstance.createDiagnostics(int(commandArguments.size()),
                                       const_cast<char **>(commandArguments.data()),
                                       new clang::TextDiagnosticPrinter(outputStream,
                                                                        compilerInstance.getDiagnosticOpts()));

    if (!compilerInstance.hasDiagnostics()) {
        mError = tr("the diagnostics engine could not be created");

        return false;
    }

    // Create an LLVM module

    mModule = new llvm::Module(tempFileName, llvm::getGlobalContext());

    // Initialise the native target, so not only can we then create a JIT
    // execution engine, but more importantly its data layout will match that of
    // our target platform...

    llvm::InitializeNativeTarget();

    // Create a JIT execution engine

    mExecutionEngine = llvm::ExecutionEngine::createJIT(mModule);

    if (!mExecutionEngine) {
        mError = tr("the JIT execution engine could not be created");

        delete mModule;

        return false;
    }

    // Create and execute the frontend to generate the LLVM assembly code,
    // making sure that all added functions end up in the same module

    llvm::OwningPtr<clang::CodeGenAction> codeGenerationAction(new clang::EmitLLVMOnlyAction(&mModule->getContext()));

    codeGenerationAction->setLinkModule(mModule);

    if (!compilerInstance.ExecuteAction(*codeGenerationAction, outputStream)) {
        mError = tr("the model could not be compiled");

        reset(false);

        return false;
    }

    // The LLVM assembly code was generated, so we can update our module

    mModule = codeGenerationAction->takeModule();

    // Everything went fine, so...

    return true;
}

//==============================================================================

void * CompilerEngine::getFunction(const QString &pFunctionName)
{
    // Return the requested function

    return mExecutionEngine?mExecutionEngine->getPointerToFunction(mModule->getFunction(qPrintable(pFunctionName))):0;
}

//==============================================================================

}   // namespace Compiler
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) Victor Titov (DeepSOIC)                                 *
 *                                           (vv.titov@gmail.com) 2015     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
#endif

#include "AttachExtension.h"

#include <Base/Console.h>
#include <App/Application.h>

#include <App/FeaturePythonPyImp.h>
#include "AttachExtensionPy.h"

using namespace Part;
using namespace Attacher;

EXTENSION_PROPERTY_SOURCE(Part::AttachExtension, App::DocumentObjectExtension);

AttachExtension::AttachExtension()
   :  _attacher(0)
{
    EXTENSION_ADD_PROPERTY_TYPE(AttacherType, ("Attacher::AttachEngine3D"), "Attachment",(App::PropertyType)(App::Prop_None),"Class name of attach engine object driving the attachment.");
    this->AttacherType.setStatus(App::Property::Status::Hidden, true);

    EXTENSION_ADD_PROPERTY_TYPE(Support, (0,0), "Attachment",(App::PropertyType)(App::Prop_None),"Support of the 2D geometry");

    EXTENSION_ADD_PROPERTY_TYPE(MapMode, (mmDeactivated), "Attachment", App::Prop_None, "Mode of attachment to other object");
    MapMode.setEnums(AttachEngine::eMapModeStrings);
    //a rough test if mode string list in Attacher.cpp is in sync with eMapMode enum.
    assert(MapMode.getEnumVector().size() == mmDummy_NumberOfModes);

    EXTENSION_ADD_PROPERTY_TYPE(MapReversed, (false), "Attachment", App::Prop_None, "Reverse Z direction (flip sketch upside down)");

    EXTENSION_ADD_PROPERTY_TYPE(MapPathParameter, (0.0), "Attachment", App::Prop_None, "Sets point of curve to map the sketch to. 0..1 = start..end");

    EXTENSION_ADD_PROPERTY_TYPE(superPlacement, (Base::Placement()), "Attachment", App::Prop_None, "Extra placement to apply in addition to attachment (in local coordinates)");

    setAttacher(new AttachEngine3D);//default attacher
    initExtensionType(AttachExtension::getExtensionClassTypeId());
}

AttachExtension::~AttachExtension()
{
    if(_attacher)
        delete _attacher;
}

void AttachExtension::setAttacher(AttachEngine* attacher)
{
    if (_attacher)
        delete _attacher;
    _attacher = attacher;
    if (_attacher){
        const char* typeName = attacher->getTypeId().getName();
        if(strcmp(this->AttacherType.getValue(),typeName)!=0) //make sure we need to change, to break recursive onChange->changeAttacherType->onChange...
            this->AttacherType.setValue(typeName);
        updateAttacherVals();
    } else {
        if (strlen(AttacherType.getValue()) != 0){ //make sure we need to change, to break recursive onChange->changeAttacherType->onChange...
            this->AttacherType.setValue("");
        }
    }
}

bool AttachExtension::changeAttacherType(const char* typeName)
{
    //check if we need to actually change anything
    if (_attacher){
        if (strcmp(_attacher->getTypeId().getName(),typeName)==0){
            return false;
        }
    } else if (strlen(typeName) == 0){
        return false;
    }
    if (strlen(typeName) == 0){
        setAttacher(nullptr);
        return true;
    }
    Base::Type t = Base::Type::fromName(typeName);
    if (t.isDerivedFrom(AttachEngine::getClassTypeId())){
        AttachEngine* pNewAttacher = static_cast<Attacher::AttachEngine*>(Base::Type::createInstanceByName(typeName));
        this->setAttacher(pNewAttacher);
        return true;
    } else {
        std::stringstream errMsg;
        errMsg << "Object if this type is not derived from AttachEngine: " << typeName;
        throw Base::Exception(errMsg.str());
    }
    assert(false);//exec shouldn't ever get here
    return false;
}

bool AttachExtension::positionBySupport()
{
    if (!_attacher)
        throw Base::RuntimeError("AttachExtension: can't positionBySupport, because no AttachEngine is set.");
    updateAttacherVals();
    try{
        getPlacement().setValue(_attacher->calculateAttachedPlacement(getPlacement().getValue()));
        return true;
    } catch (ExceptionCancel) {
        //disabled, don't do anything
        return false;
    };
}

short int AttachExtension::extensionMustExecute(void) {
    return DocumentObjectExtension::extensionMustExecute();
}

App::DocumentObjectExecReturn *AttachExtension::extensionExecute()
{
    if(this->isTouched_Mapping()) {
        try{
            positionBySupport();
        // we let all Base::Exceptions thru, so that App:DocumentObject can take appropriate action
        /*} catch (Base::Exception &e) {
            return new App::DocumentObjectExecReturn(e.what());*/
        // Convert OCC exceptions to Base::Exception
        } catch (Standard_Failure &e){
            throw Base::RuntimeError(e.GetMessageString());
//            return new App::DocumentObjectExecReturn(e.GetMessageString());
        }
    }
    return App::DocumentObjectExtension::extensionExecute();
}

void AttachExtension::extensionOnChanged(const App::Property* prop)
{
    if(! getExtendedObject()->isRestoring()){
        if ((prop == &Support
             || prop == &MapMode
             || prop == &MapPathParameter
             || prop == &MapReversed
             || prop == &superPlacement)){

            bool bAttached = false;
            try{
                bAttached = positionBySupport();
            } catch (Base::Exception &e) {
                getExtendedObject()->setStatus(App::Error, true);
                Base::Console().Error("PositionBySupport: %s",e.what());
                //set error message - how?
            } catch (Standard_Failure &e){
                getExtendedObject()->setStatus(App::Error, true);
                Base::Console().Error("PositionBySupport: %s",e.GetMessageString());
            }

            eMapMode mmode = eMapMode(this->MapMode.getValue());
            this->superPlacement.setReadOnly(!bAttached);
            getPlacement().setReadOnly(bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached.
        }

    }

    if(prop == &(this->AttacherType)){
        this->changeAttacherType(this->AttacherType.getValue());
    }

    App::DocumentObjectExtension::extensionOnChanged(prop);
}

void AttachExtension::updateAttacherVals()
{
    if (!_attacher)
        return;
    _attacher->setUp(this->Support,
                     eMapMode(this->MapMode.getValue()),
                     this->MapReversed.getValue(),
                     this->MapPathParameter.getValue(),
                     0.0,0.0,
                     this->superPlacement.getValue());
}

App::PropertyPlacement& AttachExtension::getPlacement() {

    if(!getExtendedObject()->isDerivedFrom(App::GeoFeature::getClassTypeId()))
        throw Base::RuntimeError("AttachExtension not added to GeooFeature!");

    return static_cast<App::GeoFeature*>(getExtendedObject())->Placement;
}

PyObject* AttachExtension::getExtensionPyObject(void) {

    if (ExtensionPythonObject.is(Py::_None())){
        // ref counter is set to 1
        ExtensionPythonObject = Py::Object(new AttachExtensionPy(this),true);
    }
    return Py::new_reference_to(ExtensionPythonObject);
}

namespace App {
/// @cond DOXERR
  EXTENSION_PROPERTY_SOURCE_TEMPLATE(Part::AttachExtensionPython, Part::AttachExtension)
/// @endcond

// explicit template instantiation
  template class PartExport ExtensionPythonT<Part::AttachExtension>;
}

<commit_msg>avoid permanently throwing exception by attach engine<commit_after>/***************************************************************************
 *   Copyright (c) Victor Titov (DeepSOIC)                                 *
 *                                           (vv.titov@gmail.com) 2015     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
#endif

#include "AttachExtension.h"

#include <Base/Console.h>
#include <App/Application.h>

#include <App/FeaturePythonPyImp.h>
#include "AttachExtensionPy.h"

using namespace Part;
using namespace Attacher;

EXTENSION_PROPERTY_SOURCE(Part::AttachExtension, App::DocumentObjectExtension);

AttachExtension::AttachExtension()
   :  _attacher(0)
{
    EXTENSION_ADD_PROPERTY_TYPE(AttacherType, ("Attacher::AttachEngine3D"), "Attachment",(App::PropertyType)(App::Prop_None),"Class name of attach engine object driving the attachment.");
    this->AttacherType.setStatus(App::Property::Status::Hidden, true);

    EXTENSION_ADD_PROPERTY_TYPE(Support, (0,0), "Attachment",(App::PropertyType)(App::Prop_None),"Support of the 2D geometry");

    EXTENSION_ADD_PROPERTY_TYPE(MapMode, (mmDeactivated), "Attachment", App::Prop_None, "Mode of attachment to other object");
    MapMode.setEnums(AttachEngine::eMapModeStrings);
    //a rough test if mode string list in Attacher.cpp is in sync with eMapMode enum.
    assert(MapMode.getEnumVector().size() == mmDummy_NumberOfModes);

    EXTENSION_ADD_PROPERTY_TYPE(MapReversed, (false), "Attachment", App::Prop_None, "Reverse Z direction (flip sketch upside down)");

    EXTENSION_ADD_PROPERTY_TYPE(MapPathParameter, (0.0), "Attachment", App::Prop_None, "Sets point of curve to map the sketch to. 0..1 = start..end");

    EXTENSION_ADD_PROPERTY_TYPE(superPlacement, (Base::Placement()), "Attachment", App::Prop_None, "Extra placement to apply in addition to attachment (in local coordinates)");

    setAttacher(new AttachEngine3D);//default attacher
    initExtensionType(AttachExtension::getExtensionClassTypeId());
}

AttachExtension::~AttachExtension()
{
    if(_attacher)
        delete _attacher;
}

void AttachExtension::setAttacher(AttachEngine* attacher)
{
    if (_attacher)
        delete _attacher;
    _attacher = attacher;
    if (_attacher){
        const char* typeName = attacher->getTypeId().getName();
        if(strcmp(this->AttacherType.getValue(),typeName)!=0) //make sure we need to change, to break recursive onChange->changeAttacherType->onChange...
            this->AttacherType.setValue(typeName);
        updateAttacherVals();
    } else {
        if (strlen(AttacherType.getValue()) != 0){ //make sure we need to change, to break recursive onChange->changeAttacherType->onChange...
            this->AttacherType.setValue("");
        }
    }
}

bool AttachExtension::changeAttacherType(const char* typeName)
{
    //check if we need to actually change anything
    if (_attacher){
        if (strcmp(_attacher->getTypeId().getName(),typeName)==0){
            return false;
        }
    } else if (strlen(typeName) == 0){
        return false;
    }
    if (strlen(typeName) == 0){
        setAttacher(nullptr);
        return true;
    }
    Base::Type t = Base::Type::fromName(typeName);
    if (t.isDerivedFrom(AttachEngine::getClassTypeId())){
        AttachEngine* pNewAttacher = static_cast<Attacher::AttachEngine*>(Base::Type::createInstanceByName(typeName));
        this->setAttacher(pNewAttacher);
        return true;
    } else {
        std::stringstream errMsg;
        errMsg << "Object if this type is not derived from AttachEngine: " << typeName;
        throw Base::Exception(errMsg.str());
    }
    assert(false);//exec shouldn't ever get here
    return false;
}

bool AttachExtension::positionBySupport()
{
    if (!_attacher)
        throw Base::RuntimeError("AttachExtension: can't positionBySupport, because no AttachEngine is set.");
    updateAttacherVals();
    try {
        if (_attacher->mapMode == mmDeactivated)
            return false;
        getPlacement().setValue(_attacher->calculateAttachedPlacement(getPlacement().getValue()));
        return true;
    } catch (ExceptionCancel) {
        //disabled, don't do anything
        return false;
    };
}

short int AttachExtension::extensionMustExecute(void) {
    return DocumentObjectExtension::extensionMustExecute();
}

App::DocumentObjectExecReturn *AttachExtension::extensionExecute()
{
    if(this->isTouched_Mapping()) {
        try{
            positionBySupport();
        // we let all Base::Exceptions thru, so that App:DocumentObject can take appropriate action
        /*} catch (Base::Exception &e) {
            return new App::DocumentObjectExecReturn(e.what());*/
        // Convert OCC exceptions to Base::Exception
        } catch (Standard_Failure &e){
            throw Base::RuntimeError(e.GetMessageString());
//            return new App::DocumentObjectExecReturn(e.GetMessageString());
        }
    }
    return App::DocumentObjectExtension::extensionExecute();
}

void AttachExtension::extensionOnChanged(const App::Property* prop)
{
    if(! getExtendedObject()->isRestoring()){
        if ((prop == &Support
             || prop == &MapMode
             || prop == &MapPathParameter
             || prop == &MapReversed
             || prop == &superPlacement)){

            bool bAttached = false;
            try{
                bAttached = positionBySupport();
            } catch (Base::Exception &e) {
                getExtendedObject()->setStatus(App::Error, true);
                Base::Console().Error("PositionBySupport: %s",e.what());
                //set error message - how?
            } catch (Standard_Failure &e){
                getExtendedObject()->setStatus(App::Error, true);
                Base::Console().Error("PositionBySupport: %s",e.GetMessageString());
            }

            eMapMode mmode = eMapMode(this->MapMode.getValue());
            this->superPlacement.setReadOnly(!bAttached);
            getPlacement().setReadOnly(bAttached && mmode != mmTranslate); //for mmTranslate, orientation should remain editable even when attached.
        }

    }

    if(prop == &(this->AttacherType)){
        this->changeAttacherType(this->AttacherType.getValue());
    }

    App::DocumentObjectExtension::extensionOnChanged(prop);
}

void AttachExtension::updateAttacherVals()
{
    if (!_attacher)
        return;
    _attacher->setUp(this->Support,
                     eMapMode(this->MapMode.getValue()),
                     this->MapReversed.getValue(),
                     this->MapPathParameter.getValue(),
                     0.0,0.0,
                     this->superPlacement.getValue());
}

App::PropertyPlacement& AttachExtension::getPlacement() {

    if(!getExtendedObject()->isDerivedFrom(App::GeoFeature::getClassTypeId()))
        throw Base::RuntimeError("AttachExtension not added to GeooFeature!");

    return static_cast<App::GeoFeature*>(getExtendedObject())->Placement;
}

PyObject* AttachExtension::getExtensionPyObject(void) {

    if (ExtensionPythonObject.is(Py::_None())){
        // ref counter is set to 1
        ExtensionPythonObject = Py::Object(new AttachExtensionPy(this),true);
    }
    return Py::new_reference_to(ExtensionPythonObject);
}

namespace App {
/// @cond DOXERR
  EXTENSION_PROPERTY_SOURCE_TEMPLATE(Part::AttachExtensionPython, Part::AttachExtension)
/// @endcond

// explicit template instantiation
  template class PartExport ExtensionPythonT<Part::AttachExtension>;
}

<|endoftext|>