<commit_before>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
#include <limits.h>

#include <QTest>
#include <QMetaType>
#include <QSignalSpy>
#include <QDebug>

#include <qgeopositioninfosource.h>
#include <qgeopositioninfo.h>

#include "testqgeopositioninfosource_p.h"
#include "qlocationtestutils_p.h"

Q_DECLARE_METATYPE(QGeoPositionInfoSource::PositioningMethod)
Q_DECLARE_METATYPE(QGeoPositionInfoSource::PositioningMethods)
Q_DECLARE_METATYPE(QGeoPositionInfo)

#define MAX_WAITING_TIME 50000

// Must provide a valid source, unless testing the source
// returned by QGeoPositionInfoSource::createSource() on a system
// that has no default source
#define CHECK_SOURCE_VALID { \
    if (QGeoPositionInfoSource::createSource() == 0) \
        QSKIP("No default position source on this system", SkipAll); \
    else \
        QFAIL("createTestSource() must return a valid source!"); \
}

class MyPositionSource : public QGeoPositionInfoSource
{
    Q_OBJECT
public:
    MyPositionSource(QObject *parent = 0)
        : QGeoPositionInfoSource(parent)
    {
    }

    QGeoPositionInfo lastKnownPosition(bool /*fromSatellitePositioningMethodsOnly = false*/) const
    {
        return QGeoPositionInfo();
    }

    virtual PositioningMethods supportedPositioningMethods() const { return 0; }
    virtual int minimumUpdateInterval() const { return 0; }

    virtual void startUpdates() {}
    virtual void stopUpdates() {}

    virtual void requestUpdate(int) {}
};

void TestQGeoPositionInfoSource::base_initTestCase()
{
    qRegisterMetaType<QGeoPositionInfo>();
}

void TestQGeoPositionInfoSource::base_init()
{
    m_source = createTestSource();
}

void TestQGeoPositionInfoSource::base_cleanup()
{
    delete m_source;
    m_source = 0;
}

void TestQGeoPositionInfoSource::base_cleanupTestCase()
{
}

void TestQGeoPositionInfoSource::initTestCase()
{
    base_initTestCase();
}

void TestQGeoPositionInfoSource::init()
{
    base_init();
}

void TestQGeoPositionInfoSource::cleanup()
{
    base_cleanup();
}

void TestQGeoPositionInfoSource::cleanupTestCase()
{
    base_cleanupTestCase();
}

// TC_ID_3_x_1
void TestQGeoPositionInfoSource::constructor_withParent()
{
    QLocationTestUtils::uheap_mark();
    QObject *parent = new QObject();
    new MyPositionSource(parent);
    delete parent;
    QLocationTestUtils::uheap_mark_end();
}

// TC_ID_3_x_2
void TestQGeoPositionInfoSource::constructor_noParent()
{
    QLocationTestUtils::uheap_mark();
    MyPositionSource *obj = new MyPositionSource();
    delete obj;
    QLocationTestUtils::uheap_mark_end();
}

void TestQGeoPositionInfoSource::updateInterval()
{
    MyPositionSource s;
    QCOMPARE(s.updateInterval(), 0);
}

void TestQGeoPositionInfoSource::setPreferredPositioningMethods()
{
    QFETCH(int, methods);

    MyPositionSource s;
    s.setPreferredPositioningMethods(static_cast<QGeoPositionInfoSource::PositioningMethods>(methods));
    QCOMPARE(s.preferredPositioningMethods(), static_cast<QGeoPositionInfoSource::PositioningMethods>(methods));
}

void TestQGeoPositionInfoSource::setPreferredPositioningMethods_data()
{
    QTest::addColumn<int>("methods");
    QTest::newRow("sat") << int(QGeoPositionInfoSource::SatellitePositioningMethods);
    QTest::newRow("sat | non-sat") << int(QGeoPositionInfoSource::SatellitePositioningMethods
                        | QGeoPositionInfoSource::NonSatellitePositioningMethods);
    QTest::newRow("all") << int(QGeoPositionInfoSource::AllPositioningMethods);
    QTest::newRow("all | sat") << int(QGeoPositionInfoSource::AllPositioningMethods
                                | QGeoPositionInfoSource::NonSatellitePositioningMethods);
}

void TestQGeoPositionInfoSource::preferredPositioningMethods()
{
    MyPositionSource s;
    QCOMPARE(s.preferredPositioningMethods(), 0);
}

//TC_ID_3_x_1 : Create a position source with the given parent that reads from the system's default sources of location data
void TestQGeoPositionInfoSource::createSource()
{
    QLocationTestUtils::uheap_mark();
    QObject *parent = new QObject;

    QGeoPositionInfoSource *source = QGeoPositionInfoSource::createSource(parent);
#if defined(Q_OS_SYMBIAN)
    QVERIFY(source != 0);
#else
    QVERIFY(source == 0);
#endif
    delete parent;
    QLocationTestUtils::uheap_mark_end();
}

void TestQGeoPositionInfoSource::setUpdateInterval()
{
    CHECK_SOURCE_VALID;

    QFETCH(int, interval);
    QFETCH(int, expectedInterval);

    m_source->setUpdateInterval(interval);
    QCOMPARE(m_source->updateInterval(), expectedInterval);
}

void TestQGeoPositionInfoSource::setUpdateInterval_data()
{
    QTest::addColumn<int>("interval");
    QTest::addColumn<int>("expectedInterval");

    QGeoPositionInfoSource *source = createTestSource();
    int minUpdateInterval = source ? source->minimumUpdateInterval() : -1;

    QTest::newRow("INT_MIN") << INT_MIN << minUpdateInterval;
    QTest::newRow("-1") << -1 << minUpdateInterval;
    QTest::newRow("0") << 0 << 0;
    QTest::newRow("in btw zero and minInterval") << 1 << minUpdateInterval;
    QTest::newRow("more than minInterval") << minUpdateInterval + 1 << minUpdateInterval + 1;
    QTest::newRow("less then minInterval") << minUpdateInterval - 1 << minUpdateInterval;
    QTest::newRow("equal to minInterval") << minUpdateInterval << minUpdateInterval;
    QTest::newRow("INT_MAX") << INT_MAX << INT_MAX;
}

void TestQGeoPositionInfoSource::lastKnownPosition()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source,SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    int time_out = 20000;
    m_source->setUpdateInterval(time_out);
    m_source->startUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(),1,30000);

    QList<QVariant> list = spy.takeFirst();
    QGeoPositionInfo info;
    info = list.at(0).value<QGeoPositionInfo>();
    QGeoPositionInfo lastPositioninfo;
    lastPositioninfo = m_source->lastKnownPosition();
    QCOMPARE(info.coordinate(),lastPositioninfo.coordinate());
    QCOMPARE(info.dateTime(),lastPositioninfo.dateTime());

    QCOMPARE(qFuzzyCompare(info.property(QGeoPositionInfo::HorizontalAccuracy),
            lastPositioninfo.property(QGeoPositionInfo::HorizontalAccuracy)),TRUE);

    QCOMPARE(qFuzzyCompare(info.property(QGeoPositionInfo::VerticalAccuracy),
            lastPositioninfo.property(QGeoPositionInfo::VerticalAccuracy)),TRUE);
}

void TestQGeoPositionInfoSource::minimumUpdateInterval()
{
    CHECK_SOURCE_VALID;

    QVERIFY(m_source->minimumUpdateInterval() > 0);
}

//TC_ID_3_x_1
void TestQGeoPositionInfoSource::startUpdates_testIntervals()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->setUpdateInterval(8000);
    int interval = m_source->updateInterval();

    m_source->startUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000);
    for (int i=0; i<9; i++) {
        QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, (interval*3));
        spy.clear();
    }

// TODO Currently updates are coming irregularly from S60
#if !defined(Q_OS_SYMBIAN)
    for (int i=0; i<9; i++) {
        QTRY_COMPARE_WITH_TIMEOUT_RANGE(spy.count(), 1, 7000, 10000);
        spy.clear();
    }
#endif
    m_source->stopUpdates();
}

//TC_ID_3_x_2
void TestQGeoPositionInfoSource::startUpdates_testDefaultInterval()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->startUpdates();
    for (int i=0; i<3; i++) {
        QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 3000);
        spy.clear();
    }
    m_source->stopUpdates();
}

//TC_ID_3_x_3
void TestQGeoPositionInfoSource::startUpdates_testZeroInterval()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->setUpdateInterval(0);
    m_source->startUpdates();
    for (int i=0; i<3; i++) {
        QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 3000);
        spy.clear();
    }
    m_source->stopUpdates();
}

//TC_ID_3_x_1
void TestQGeoPositionInfoSource::stopUpdates()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->setUpdateInterval(8000);
    m_source->startUpdates();
    for (int i=0; i<2; i++) {
        QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 10000);
        spy.clear();
    }
    m_source->stopUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 0, 10000);
    spy.clear();

    m_source->setUpdateInterval(0);
    m_source->startUpdates();
    m_source->stopUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 0, 10000);
}

//TC_ID_3_x_2
void TestQGeoPositionInfoSource::stopUpdates_withoutStart()
{
    CHECK_SOURCE_VALID;

    m_source->stopUpdates(); // check there is no crash
}

void TestQGeoPositionInfoSource::requestUpdate()
{
    CHECK_SOURCE_VALID;

    QFETCH(int, timeout);
    QSignalSpy spy(m_source, SIGNAL(requestTimeout()));
    m_source->requestUpdate(timeout);
    QTRY_COMPARE(spy.count(), 1);
}

void TestQGeoPositionInfoSource::requestUpdate_data()
{
    QTest::addColumn<int>("timeout");
    QTest::newRow("zero") << 0;                     //TC_ID_3_x_6
    QTest::newRow("less than zero") << -1;          //TC_ID_3_x_7
}

// TC_ID_3_x_1 : Create position source and call requestUpdate with valid timeout value
void TestQGeoPositionInfoSource::requestUpdate_validTimeout()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spyUpdate(m_source, SIGNAL(positionUpdated(QGeoPositionInfo)));
    m_source->requestUpdate(20000);
    //Q_WAIT(spyUpdate.count(), 1, 20000);
    //QCOMPARE(spyUpdate.count(),1);
    QTRY_COMPARE_WITH_TIMEOUT(spyUpdate.count(), 1, 20000);
    spyUpdate.clear();
}

// TC_ID_3_x_2 : Create position source and call requestUpdate with a timeout less than minimumupdateInterval
void TestQGeoPositionInfoSource::requestUpdate_timeoutLessThanMinimumInterval()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spyTimeout(m_source, SIGNAL(requestTimeout()));
    m_source->requestUpdate(1);
    //Q_WAIT(spyTimeout.count(), 1, 10);
    //QCOMPARE(spyTimeout.count(), 1);
    QTRY_COMPARE_WITH_TIMEOUT(spyTimeout.count(), 1, 10);
    spyTimeout.clear();
}

// TC_ID_3_x_3 : Call requestUpdate() with same value repeatedly
void TestQGeoPositionInfoSource::requestUpdate_repeatedCalls()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spyUpdate(m_source, SIGNAL(positionUpdated(QGeoPositionInfo)));
    m_source->requestUpdate(20000);
    //Q_WAIT(spyUpdate.count(), 1, 20000);
    //QCOMPARE(spyUpdate.count(), 1);
    QTRY_COMPARE_WITH_TIMEOUT(spyUpdate.count(), 1, 20000);
    spyUpdate.clear();
    m_source->requestUpdate(20000);
    //Q_WAIT(spyUpdate.count(), 1, 20000);
    //QCOMPARE(spyUpdate.count(),1);
    QTRY_COMPARE_WITH_TIMEOUT(spyUpdate.count(), 1, 20000);
    spyUpdate.clear();
}

//TC_ID_3_x_4
void TestQGeoPositionInfoSource::requestUpdate_withUpdateInterval()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->setUpdateInterval(MAX_WAITING_TIME);
    m_source->startUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, MAX_WAITING_TIME);
    m_source->requestUpdate(25000);

    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 27000);
    m_source->stopUpdates();
}

#include "testqgeopositioninfosource.moc"
<commit_msg>Fix tests where conditions fail if an additional position update is received because the QTRY_* function has not stopped immediately after the first update is received (due to qWait()).<commit_after>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
#include <limits.h>

#include <QTest>
#include <QMetaType>
#include <QSignalSpy>
#include <QDebug>
#include <QTimer>

#include <qgeopositioninfosource.h>
#include <qgeopositioninfo.h>

#include "testqgeopositioninfosource_p.h"
#include "qlocationtestutils_p.h"

Q_DECLARE_METATYPE(QGeoPositionInfoSource::PositioningMethod)
Q_DECLARE_METATYPE(QGeoPositionInfoSource::PositioningMethods)
Q_DECLARE_METATYPE(QGeoPositionInfo)

#define MAX_WAITING_TIME 50000

// Must provide a valid source, unless testing the source
// returned by QGeoPositionInfoSource::createSource() on a system
// that has no default source
#define CHECK_SOURCE_VALID { \
    if (!m_source) { \
        if (QGeoPositionInfoSource::createSource() == 0) \
            QSKIP("No default position source on this system", SkipAll); \
        else \
            QFAIL("createTestSource() must return a valid source!"); \
    } \
}

class MyPositionSource : public QGeoPositionInfoSource
{
    Q_OBJECT
public:
    MyPositionSource(QObject *parent = 0)
        : QGeoPositionInfoSource(parent)
    {
    }

    QGeoPositionInfo lastKnownPosition(bool /*fromSatellitePositioningMethodsOnly = false*/) const
    {
        return QGeoPositionInfo();
    }

    virtual PositioningMethods supportedPositioningMethods() const { return 0; }
    virtual int minimumUpdateInterval() const { return 0; }

    virtual void startUpdates() {}
    virtual void stopUpdates() {}

    virtual void requestUpdate(int) {}
};

void TestQGeoPositionInfoSource::base_initTestCase()
{
    qRegisterMetaType<QGeoPositionInfo>();
}

void TestQGeoPositionInfoSource::base_init()
{
    m_source = createTestSource();
}

void TestQGeoPositionInfoSource::base_cleanup()
{
    delete m_source;
    m_source = 0;
}

void TestQGeoPositionInfoSource::base_cleanupTestCase()
{
}

void TestQGeoPositionInfoSource::initTestCase()
{
    base_initTestCase();
}

void TestQGeoPositionInfoSource::init()
{
    base_init();
}

void TestQGeoPositionInfoSource::cleanup()
{
    base_cleanup();
}

void TestQGeoPositionInfoSource::cleanupTestCase()
{
    base_cleanupTestCase();
}

// TC_ID_3_x_1
void TestQGeoPositionInfoSource::constructor_withParent()
{
    QLocationTestUtils::uheap_mark();
    QObject *parent = new QObject();
    new MyPositionSource(parent);
    delete parent;
    QLocationTestUtils::uheap_mark_end();
}

// TC_ID_3_x_2
void TestQGeoPositionInfoSource::constructor_noParent()
{
    QLocationTestUtils::uheap_mark();
    MyPositionSource *obj = new MyPositionSource();
    delete obj;
    QLocationTestUtils::uheap_mark_end();
}

void TestQGeoPositionInfoSource::updateInterval()
{
    MyPositionSource s;
    QCOMPARE(s.updateInterval(), 0);
}

void TestQGeoPositionInfoSource::setPreferredPositioningMethods()
{
    QFETCH(int, methods);

    MyPositionSource s;
    s.setPreferredPositioningMethods(static_cast<QGeoPositionInfoSource::PositioningMethods>(methods));
    QCOMPARE(s.preferredPositioningMethods(), static_cast<QGeoPositionInfoSource::PositioningMethods>(methods));
}

void TestQGeoPositionInfoSource::setPreferredPositioningMethods_data()
{
    QTest::addColumn<int>("methods");
    QTest::newRow("sat") << int(QGeoPositionInfoSource::SatellitePositioningMethods);
    QTest::newRow("sat | non-sat") << int(QGeoPositionInfoSource::SatellitePositioningMethods
                        | QGeoPositionInfoSource::NonSatellitePositioningMethods);
    QTest::newRow("all") << int(QGeoPositionInfoSource::AllPositioningMethods);
    QTest::newRow("all | sat") << int(QGeoPositionInfoSource::AllPositioningMethods
                                | QGeoPositionInfoSource::NonSatellitePositioningMethods);
}

void TestQGeoPositionInfoSource::preferredPositioningMethods()
{
    MyPositionSource s;
    QCOMPARE(s.preferredPositioningMethods(), 0);
}

//TC_ID_3_x_1 : Create a position source with the given parent that reads from the system's default sources of location data
void TestQGeoPositionInfoSource::createSource()
{
    QLocationTestUtils::uheap_mark();
    QObject *parent = new QObject;

    QGeoPositionInfoSource *source = QGeoPositionInfoSource::createSource(parent);
#if defined(Q_OS_SYMBIAN)
    QVERIFY(source != 0);
#else
    QVERIFY(source == 0);
#endif
    delete parent;
    QLocationTestUtils::uheap_mark_end();
}

void TestQGeoPositionInfoSource::setUpdateInterval()
{
    CHECK_SOURCE_VALID;

    QFETCH(int, interval);
    QFETCH(int, expectedInterval);

    m_source->setUpdateInterval(interval);
    QCOMPARE(m_source->updateInterval(), expectedInterval);
}

void TestQGeoPositionInfoSource::setUpdateInterval_data()
{
    QTest::addColumn<int>("interval");
    QTest::addColumn<int>("expectedInterval");

    QGeoPositionInfoSource *source = createTestSource();
    int minUpdateInterval = source ? source->minimumUpdateInterval() : -1;

    QTest::newRow("INT_MIN") << INT_MIN << minUpdateInterval;
    QTest::newRow("-1") << -1 << minUpdateInterval;
    QTest::newRow("0") << 0 << 0;
    QTest::newRow("in btw zero and minInterval") << 1 << minUpdateInterval;
    QTest::newRow("more than minInterval") << minUpdateInterval + 1 << minUpdateInterval + 1;
    QTest::newRow("less then minInterval") << minUpdateInterval - 1 << minUpdateInterval;
    QTest::newRow("equal to minInterval") << minUpdateInterval << minUpdateInterval;
    QTest::newRow("INT_MAX") << INT_MAX << INT_MAX;
}

void TestQGeoPositionInfoSource::lastKnownPosition()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source,SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    int time_out = 20000;
    m_source->setUpdateInterval(time_out);
    m_source->startUpdates();
    //QTRY_COMPARE_WITH_TIMEOUT(spy.count(),1,30000);

    // Use QEventLoop instead of qWait() to ensure we stop as soon as a
    // position is emitted (otherwise the lastKnownPosition() may have
    // changed by the time it is checked)
    QEventLoop loop;
    QTimer timer;
    timer.setInterval(30000);
    connect(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)),
            &loop, SLOT(quit()));
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    timer.start();
    loop.exec();
    QCOMPARE(spy.count(), 1);

    QList<QVariant> list = spy.takeFirst();
    QGeoPositionInfo info;
    info = list.at(0).value<QGeoPositionInfo>();
    QGeoPositionInfo lastPositioninfo;
    lastPositioninfo = m_source->lastKnownPosition();
    QCOMPARE(info.coordinate(),lastPositioninfo.coordinate());
    QCOMPARE(info.dateTime(),lastPositioninfo.dateTime());

    QCOMPARE(qFuzzyCompare(info.property(QGeoPositionInfo::HorizontalAccuracy),
            lastPositioninfo.property(QGeoPositionInfo::HorizontalAccuracy)),TRUE);

    QCOMPARE(qFuzzyCompare(info.property(QGeoPositionInfo::VerticalAccuracy),
            lastPositioninfo.property(QGeoPositionInfo::VerticalAccuracy)),TRUE);
}

void TestQGeoPositionInfoSource::minimumUpdateInterval()
{
    CHECK_SOURCE_VALID;

    QVERIFY(m_source->minimumUpdateInterval() > 0);
}

//TC_ID_3_x_1
void TestQGeoPositionInfoSource::startUpdates_testIntervals()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->setUpdateInterval(8000);
    int interval = m_source->updateInterval();

    m_source->startUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000);
    for (int i=0; i<9; i++) {
        QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, (interval*3));
        spy.clear();
    }

// TODO Currently updates are coming irregularly from S60
#if !defined(Q_OS_SYMBIAN)
    for (int i=0; i<9; i++) {
        QTRY_COMPARE_WITH_TIMEOUT_RANGE(spy.count(), 1, 7000, 10000);
        spy.clear();
    }
#endif
    m_source->stopUpdates();
}

//TC_ID_3_x_2
void TestQGeoPositionInfoSource::startUpdates_testDefaultInterval()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->startUpdates();
    for (int i=0; i<3; i++) {
        QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, 3000);
        spy.clear();
    }
    m_source->stopUpdates();
}

//TC_ID_3_x_3
void TestQGeoPositionInfoSource::startUpdates_testZeroInterval()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->setUpdateInterval(0);
    m_source->startUpdates();
    for (int i=0; i<3; i++) {
        QTRY_VERIFY_WITH_TIMEOUT(spy.count() > 0, 3000);
        spy.clear();
    }
    m_source->stopUpdates();
}

//TC_ID_3_x_1
void TestQGeoPositionInfoSource::stopUpdates()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->setUpdateInterval(8000);
    m_source->startUpdates();
    for (int i=0; i<2; i++) {
        QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 10000);
        spy.clear();
    }
    m_source->stopUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 0, 10000);
    spy.clear();

    m_source->setUpdateInterval(0);
    m_source->startUpdates();
    m_source->stopUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 0, 10000);
}

//TC_ID_3_x_2
void TestQGeoPositionInfoSource::stopUpdates_withoutStart()
{
    CHECK_SOURCE_VALID;

    m_source->stopUpdates(); // check there is no crash
}

void TestQGeoPositionInfoSource::requestUpdate()
{
    CHECK_SOURCE_VALID;

    QFETCH(int, timeout);
    QSignalSpy spy(m_source, SIGNAL(requestTimeout()));
    m_source->requestUpdate(timeout);
    QTRY_COMPARE(spy.count(), 1);
}

void TestQGeoPositionInfoSource::requestUpdate_data()
{
    QTest::addColumn<int>("timeout");
    QTest::newRow("zero") << 0;                     //TC_ID_3_x_6
    QTest::newRow("less than zero") << -1;          //TC_ID_3_x_7
}

// TC_ID_3_x_1 : Create position source and call requestUpdate with valid timeout value
void TestQGeoPositionInfoSource::requestUpdate_validTimeout()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spyUpdate(m_source, SIGNAL(positionUpdated(QGeoPositionInfo)));
    m_source->requestUpdate(20000);
    //Q_WAIT(spyUpdate.count(), 1, 20000);
    //QCOMPARE(spyUpdate.count(),1);
    QTRY_COMPARE_WITH_TIMEOUT(spyUpdate.count(), 1, 20000);
    spyUpdate.clear();
}

// TC_ID_3_x_2 : Create position source and call requestUpdate with a timeout less than minimumupdateInterval
void TestQGeoPositionInfoSource::requestUpdate_timeoutLessThanMinimumInterval()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spyTimeout(m_source, SIGNAL(requestTimeout()));
    m_source->requestUpdate(1);
    //Q_WAIT(spyTimeout.count(), 1, 10);
    //QCOMPARE(spyTimeout.count(), 1);
    QTRY_COMPARE_WITH_TIMEOUT(spyTimeout.count(), 1, 10);
    spyTimeout.clear();
}

// TC_ID_3_x_3 : Call requestUpdate() with same value repeatedly
void TestQGeoPositionInfoSource::requestUpdate_repeatedCalls()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spyUpdate(m_source, SIGNAL(positionUpdated(QGeoPositionInfo)));
    m_source->requestUpdate(20000);
    //Q_WAIT(spyUpdate.count(), 1, 20000);
    //QCOMPARE(spyUpdate.count(), 1);
    QTRY_COMPARE_WITH_TIMEOUT(spyUpdate.count(), 1, 20000);
    spyUpdate.clear();
    m_source->requestUpdate(20000);
    //Q_WAIT(spyUpdate.count(), 1, 20000);
    //QCOMPARE(spyUpdate.count(),1);
    QTRY_COMPARE_WITH_TIMEOUT(spyUpdate.count(), 1, 20000);
    spyUpdate.clear();
}

//TC_ID_3_x_4
void TestQGeoPositionInfoSource::requestUpdate_withUpdateInterval()
{
    CHECK_SOURCE_VALID;

    QSignalSpy spy(m_source, SIGNAL(positionUpdated(const QGeoPositionInfo&)));
    m_source->setUpdateInterval(MAX_WAITING_TIME);
    m_source->startUpdates();
    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, MAX_WAITING_TIME);
    m_source->requestUpdate(25000);

    QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 27000);
    m_source->stopUpdates();
}

#include "testqgeopositioninfosource.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2015 John Connor (BM-NC49AxAjcqVcF5jNPu85Rb8MJ2d9JqZt)
 *
 * This file is part of vanillacoin.
 *
 * vanillacoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef COIN_CHAINBLENDER_HPP
#define COIN_CHAINBLENDER_HPP

#include <mutex>

namespace coin {

    /**
     * Implements a chainblender mechanism.
     */
    class chainblender
    {
        public:

            /**
             * Constructor
             */
            chainblender();

            /**
             * The singleton accessor.
             */
            static chainblender & instance();

        private:

            // ...

        protected:

            /**
             * The std::mutex.
             */
            static std::mutex mutex_;
    };

} // namespace coin

#endif // COIN_CHAINBLENDER_HPP
<commit_msg>chainblender partial merge<commit_after>/*
 * Copyright (c) 2013-2015 John Connor (BM-NC49AxAjcqVcF5jNPu85Rb8MJ2d9JqZt)
 *
 * This file is part of vanillacoin.
 *
 * vanillacoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef COIN_CHAINBLENDER_HPP
#define COIN_CHAINBLENDER_HPP

#include <cstdint>
#include <map>
#include <mutex>
#include <set>

#include <boost/asio.hpp>

#include <coin/sha256.hpp>

namespace coin {

    /**
     * Implements a chainblender mechanism.
     */
    class chainblender
    {
        public:

            /**
             * A session.
             */
            typedef struct
            {
                sha256 hash_id;
                std::int64_t denomination;
                std::time_t time;
                std::uint8_t participants;
                bool is_active;
            } session_t;

            /**
             * k
             */
            enum { k = 8 };

            /**
             * n
             */
            enum { n = 2 };

            /**
             * Constructor
             */
            chainblender();

            /**
             * The singleton accessor.
             */
            static chainblender & instance();

            /**
             * Create the denominations.
             */
            std::set<std::int64_t> denominations();

            /**
             * Calculates the score of a chainblender relay node.
             * @param ep The boost::asio::ip::tcp::endpoint.
             */
            std::int16_t calculate_score(
                const boost::asio::ip::tcp::endpoint & ep
            );

            /**
             * The sessions.
             */
            std::map<sha256, session_t> & sessions();

        private:

            /**
             * The sessions.
             */
            std::map<sha256, session_t> m_sessions;

        protected:

            /**
             * The std::mutex.
             */
            static std::mutex mutex_;
    };

} // namespace coin

#endif // COIN_CHAINBLENDER_HPP
<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "itkKurtosisFitFunctor.h"
#include <iostream>
#include <iomanip>

void itk::KurtosisFitFunctor::operator()(vnl_matrix<double> & newSignal, const vnl_matrix<double> & SignalMatrix, const double & S0)
{

  vnl_vector<double> initalGuess(2);
  // initialize Least Squres Function
  // SignalMatrix.cols() defines the number of shells points
  lestSquaresFunction model(SignalMatrix.cols());
  model.set_bvalues(m_BValueList);// set BValue Vector e.g.: [1000, 2000, 3000] <- shell b Values

  // initialize Levenberg Marquardt
  vnl_levenberg_marquardt minimizer(model);
  minimizer.set_max_function_evals(1000); // Iterations
  minimizer.set_f_tolerance(1e-10);        // Function tolerance

  // for each Direction calculate LSF Coeffs ADC & AKC
  for(unsigned int i = 0 ; i < SignalMatrix.rows(); i++)
  {
    model.set_measurements(SignalMatrix.get_row(i));
    model.set_reference_measurement(S0);

    initalGuess.put(0, 0.f); // ADC
    initalGuess.put(1, 0.8f); // AKC

    // start Levenberg-Marquardt
    minimizer.minimize_without_gradient(initalGuess);

    const double & ADC = initalGuess.get(0);
    const double & AKC = initalGuess.get(1);

    newSignal.put(i, 0, S0 * std::exp(-m_TargetBvalue * ADC + 1./6. * m_TargetBvalue* m_TargetBvalue * ADC * ADC * AKC));
    newSignal.put(i, 1, minimizer.get_end_error()); // RMS Error

    //OUTPUT FOR EVALUATION

    std::cout << std::scientific << std::setprecision(5)
              << initalGuess[0] << ","                  // fitted ADC
              << initalGuess[1] << ","                  // fitted AKC
              << S0 << ","                              // S0 value
              << minimizer.get_end_error() << ",";      // End error
    for(unsigned int j = 0; j < SignalMatrix.get_row(i).size(); j++ ){
      std::cout << std::scientific << std::setprecision(5) << SignalMatrix.get_row(i)[j];    // S_n Values corresponding to shell 1 to shell n
      if(j != SignalMatrix.get_row(i).size()-1) std::cout << ",";
    }
    std::cout << std::endl;
  }
}
<commit_msg>comment out evaluation output<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "itkKurtosisFitFunctor.h"
#include <iostream>
#include <iomanip>

void itk::KurtosisFitFunctor::operator()(vnl_matrix<double> & newSignal, const vnl_matrix<double> & SignalMatrix, const double & S0)
{

  vnl_vector<double> initalGuess(2);
  // initialize Least Squres Function
  // SignalMatrix.cols() defines the number of shells points
  lestSquaresFunction model(SignalMatrix.cols());
  model.set_bvalues(m_BValueList);// set BValue Vector e.g.: [1000, 2000, 3000] <- shell b Values

  // initialize Levenberg Marquardt
  vnl_levenberg_marquardt minimizer(model);
  minimizer.set_max_function_evals(1000); // Iterations
  minimizer.set_f_tolerance(1e-10);        // Function tolerance

  // for each Direction calculate LSF Coeffs ADC & AKC
  for(unsigned int i = 0 ; i < SignalMatrix.rows(); i++)
  {
    model.set_measurements(SignalMatrix.get_row(i));
    model.set_reference_measurement(S0);

    initalGuess.put(0, 0.f); // ADC
    initalGuess.put(1, 0.8f); // AKC

    // start Levenberg-Marquardt
    minimizer.minimize_without_gradient(initalGuess);

    const double & ADC = initalGuess.get(0);
    const double & AKC = initalGuess.get(1);

    newSignal.put(i, 0, S0 * std::exp(-m_TargetBvalue * ADC + 1./6. * m_TargetBvalue* m_TargetBvalue * ADC * ADC * AKC));
    newSignal.put(i, 1, minimizer.get_end_error()); // RMS Error

    //OUTPUT FOR EVALUATION

    /*std::cout << std::scientific << std::setprecision(5)
              << initalGuess[0] << ","                  // fitted ADC
              << initalGuess[1] << ","                  // fitted AKC
              << S0 << ","                              // S0 value
              << minimizer.get_end_error() << ",";      // End error
    for(unsigned int j = 0; j < SignalMatrix.get_row(i).size(); j++ ){
      std::cout << std::scientific << std::setprecision(5) << SignalMatrix.get_row(i)[j];    // S_n Values corresponding to shell 1 to shell n
      if(j != SignalMatrix.get_row(i).size()-1) std::cout << ",";
    }
    std::cout << std::endl;*/
  }
}
<|endoftext|>


<commit_before>/****************************************************************/
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*          All contents are licensed under LGPL V2.1           */
/*             See LICENSE for full restrictions                */
/****************************************************************/

#include "ComputePolycrystalElasticityTensor.h"
#include "RotationTensor.h"

template<>
InputParameters validParams<ComputePolycrystalElasticityTensor>()
{
  InputParameters params = validParams<ComputeElasticityTensorBase>();
  params.addClassDescription("Compute an evolving elasticity tensor coupled to a grain growth phase field model.");
  params.addRequiredParam<UserObjectName>("grain_tracker", "Name of GrainTracker user object that provides RankFourTensors");
  params.addParam<Real>("length_scale", 1.0e-9, "Lengthscale of the problem, in meters");
  params.addParam<Real>("pressure_scale", 1.0e6, "Pressure scale of the problem, in pa");
  params.addRequiredCoupledVarWithAutoBuild("v", "var_name_base", "op_num", "Array of coupled variables");
  return params;
}

ComputePolycrystalElasticityTensor::ComputePolycrystalElasticityTensor(const InputParameters & parameters) :
    ComputeElasticityTensorBase(parameters),
    _length_scale(getParam<Real>("length_scale")),
    _pressure_scale(getParam<Real>("pressure_scale")),
    _grain_tracker(getUserObject<GrainDataTracker<RankFourTensor>>("grain_tracker")),
    _op_num(coupledComponents("v")),
    _vals(_op_num),
    _D_elastic_tensor(_op_num),
    _JtoeV(6.24150974e18)
{
  // Loop over variables (ops)
  for (unsigned int op = 0; op < _op_num; ++op)
  {
    // Initialize variables
    _vals[op] = &coupledValue("v", op);

    // declare elasticity tensor derivative properties
    _D_elastic_tensor[op] = &declarePropertyDerivative<RankFourTensor>(_elasticity_tensor_name, getVar("v", op)->name());
  }
}

void
ComputePolycrystalElasticityTensor::computeQpElasticityTensor()
{
  // Get list of active order parameters from grain tracker
  const std::vector<std::pair<unsigned int, unsigned int> > & active_ops = _grain_tracker.getElementalValues(_current_elem->id());
  unsigned int n_active_ops = active_ops.size();

  if (n_active_ops < 1 && _t_step > 0)
    mooseError("No active order parameters");

  // Calculate elasticity tensor
  _elasticity_tensor[_qp].zero();
  Real sum_h = 0.0;
  for (unsigned int op = 0; op < n_active_ops; ++op)
  {
    const unsigned int grain_index = active_ops[op].first;
    const unsigned int op_index = active_ops[op].second;

    // Interpolation factor for elasticity tensors
    Real h = (1.0 + std::sin(libMesh::pi * ((*_vals[op_index])[_qp] - 0.5))) / 2.0;

    // Sum all rotated elasticity tensors
    _elasticity_tensor[_qp] += _grain_tracker.getData(grain_index) * h;
    sum_h += h;
  }

  const Real tol = 1.0e-10;
  sum_h = std::max(sum_h, tol);
  _elasticity_tensor[_qp] /= sum_h;

  // Calculate elasticity tensor derivative: Cderiv = dhdopi/sum_h * (Cop - _Cijkl)
  for (unsigned int op = 0; op < _op_num; ++op)
    (*_D_elastic_tensor[op])[_qp].zero();

  for (unsigned int op = 0; op < n_active_ops; ++op)
  {
    const unsigned int grain_index = active_ops[op].first;
    const unsigned int op_index = active_ops[op].second;

    Real dhdopi = libMesh::pi * std::cos(libMesh::pi * ((*_vals[op_index])[_qp] - 0.5)) / 2.0;
    RankFourTensor & C_deriv = (*_D_elastic_tensor[op_index])[_qp];

    C_deriv = (_grain_tracker.getData(grain_index) - _elasticity_tensor[_qp]) * dhdopi / sum_h;

    // Convert from XPa to eV/(xm)^3, where X is pressure scale and x is length scale;
    C_deriv *= _JtoeV * (_length_scale * _length_scale * _length_scale) * _pressure_scale;
  }
}
<commit_msg>removing error message (#7685)<commit_after>/****************************************************************/
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*          All contents are licensed under LGPL V2.1           */
/*             See LICENSE for full restrictions                */
/****************************************************************/

#include "ComputePolycrystalElasticityTensor.h"
#include "RotationTensor.h"

template<>
InputParameters validParams<ComputePolycrystalElasticityTensor>()
{
  InputParameters params = validParams<ComputeElasticityTensorBase>();
  params.addClassDescription("Compute an evolving elasticity tensor coupled to a grain growth phase field model.");
  params.addRequiredParam<UserObjectName>("grain_tracker", "Name of GrainTracker user object that provides RankFourTensors");
  params.addParam<Real>("length_scale", 1.0e-9, "Lengthscale of the problem, in meters");
  params.addParam<Real>("pressure_scale", 1.0e6, "Pressure scale of the problem, in pa");
  params.addRequiredCoupledVarWithAutoBuild("v", "var_name_base", "op_num", "Array of coupled variables");
  return params;
}

ComputePolycrystalElasticityTensor::ComputePolycrystalElasticityTensor(const InputParameters & parameters) :
    ComputeElasticityTensorBase(parameters),
    _length_scale(getParam<Real>("length_scale")),
    _pressure_scale(getParam<Real>("pressure_scale")),
    _grain_tracker(getUserObject<GrainDataTracker<RankFourTensor>>("grain_tracker")),
    _op_num(coupledComponents("v")),
    _vals(_op_num),
    _D_elastic_tensor(_op_num),
    _JtoeV(6.24150974e18)
{
  // Loop over variables (ops)
  for (unsigned int op = 0; op < _op_num; ++op)
  {
    // Initialize variables
    _vals[op] = &coupledValue("v", op);

    // declare elasticity tensor derivative properties
    _D_elastic_tensor[op] = &declarePropertyDerivative<RankFourTensor>(_elasticity_tensor_name, getVar("v", op)->name());
  }
}

void
ComputePolycrystalElasticityTensor::computeQpElasticityTensor()
{
  // Get list of active order parameters from grain tracker
  const std::vector<std::pair<unsigned int, unsigned int> > & active_ops = _grain_tracker.getElementalValues(_current_elem->id());
  unsigned int n_active_ops = active_ops.size();

  // Calculate elasticity tensor
  _elasticity_tensor[_qp].zero();
  Real sum_h = 0.0;
  for (unsigned int op = 0; op < n_active_ops; ++op)
  {
    const unsigned int grain_index = active_ops[op].first;
    const unsigned int op_index = active_ops[op].second;

    // Interpolation factor for elasticity tensors
    Real h = (1.0 + std::sin(libMesh::pi * ((*_vals[op_index])[_qp] - 0.5))) / 2.0;

    // Sum all rotated elasticity tensors
    _elasticity_tensor[_qp] += _grain_tracker.getData(grain_index) * h;
    sum_h += h;
  }

  const Real tol = 1.0e-10;
  sum_h = std::max(sum_h, tol);
  _elasticity_tensor[_qp] /= sum_h;

  // Calculate elasticity tensor derivative: Cderiv = dhdopi/sum_h * (Cop - _Cijkl)
  for (unsigned int op = 0; op < _op_num; ++op)
    (*_D_elastic_tensor[op])[_qp].zero();

  for (unsigned int op = 0; op < n_active_ops; ++op)
  {
    const unsigned int grain_index = active_ops[op].first;
    const unsigned int op_index = active_ops[op].second;

    Real dhdopi = libMesh::pi * std::cos(libMesh::pi * ((*_vals[op_index])[_qp] - 0.5)) / 2.0;
    RankFourTensor & C_deriv = (*_D_elastic_tensor[op_index])[_qp];

    C_deriv = (_grain_tracker.getData(grain_index) - _elasticity_tensor[_qp]) * dhdopi / sum_h;

    // Convert from XPa to eV/(xm)^3, where X is pressure scale and x is length scale;
    C_deriv *= _JtoeV * (_length_scale * _length_scale * _length_scale) * _pressure_scale;
  }
}
<|endoftext|>


<commit_before>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "precomp.h"

using namespace Dml;

TensorDesc::TensorDesc(
    DML_TENSOR_DATA_TYPE dataType,
    gsl::span<const uint32_t> sizes,
    std::optional<gsl::span<const uint32_t>> strides,
    uint32_t guaranteedBaseOffsetAlignment
    )
{
    m_tensorType = DML_TENSOR_TYPE_BUFFER;
    m_bufferTensorDesc.DataType = dataType;
    m_mlOperatorTensorDataType = GetMlDataTypeFromDmlDataType(dataType);

    ML_CHECK_VALID_ARGUMENT(gsl::narrow_cast<size_t>(sizes.size()) <= std::size(m_sizes));
    std::copy(sizes.begin(), sizes.end(), m_sizes);
    m_bufferTensorDesc.Sizes = m_sizes;

    if (strides)
    {
        ML_CHECK_VALID_ARGUMENT(strides->size() == sizes.size());
        std::copy(strides->begin(), strides->end(), m_strides);
        m_bufferTensorDesc.Strides = m_strides;
    }

    m_bufferTensorDesc.DimensionCount = gsl::narrow_cast<uint32_t>(sizes.size());
    m_bufferTensorDesc.Flags = DML_TENSOR_FLAG_NONE;

    m_bufferTensorDesc.GuaranteedBaseOffsetAlignment = guaranteedBaseOffsetAlignment;
    m_bufferTensorDesc.TotalTensorSizeInBytes = DMLCalcBufferTensorSize(
        m_bufferTensorDesc.DataType,
        m_bufferTensorDesc.DimensionCount,
        m_sizes,
        strides ? m_strides : nullptr
        );
}

TensorDesc::TensorDesc(MLOperatorTensorDataType dataType)
{
    m_mlOperatorTensorDataType = dataType;
    m_bufferTensorDesc.DataType = GetDmlDataTypeFromMlDataType(dataType);
    // Leave all other fields deferred, including m_tensorType = DML_TENSOR_TYPE_INVALID.
}

TensorDesc::TensorDesc(
    MLOperatorTensorDataType dataType,
    gsl::span<const uint32_t> dimensions,
    gsl::span<const uint32_t> nonBroadcastDimensions,
    uint32_t coerceAxis,
    int32_t placement, // Adjustment offset of the passed dimensions within the minDimensionCount.
    int32_t leftAlignedDimensionCount, // Number of dimensions that remain left aligned when expanded to minimum count (INT32_MAX means all, 0 means all right aligned).
    uint32_t minDimensionCount,
    uint32_t guaranteedBaseOffsetAlignment
    )
{
    m_tensorType = DML_TENSOR_TYPE_BUFFER;
    m_mlOperatorTensorDataType = dataType;

    m_bufferTensorDesc.DataType = GetDmlDataTypeFromMlDataType(dataType);
    ML_CHECK_VALID_ARGUMENT(ApiTraits::IsValidEnumValue(m_bufferTensorDesc.DataType));

    // Flattening coercion isn't always possible when striding is used to broadcast tensors.
    // Also, placement and split alignment is not implemented in combination with broadcasting.
    ML_CHECK_VALID_ARGUMENT((nonBroadcastDimensions == dimensions)
                        || ((coerceAxis == TensorAxis::DoNotCoerce) && (placement == W) && (leftAlignedDimensionCount == RightAligned)));

    gsl::span<const uint32_t> sizes;

    // If needed, flatten the tensor dimensions to a 2D tensor of size [a_0 * ... * a_{coerceAxis-1}, a_{coerceAxis} * ... * a_{n-1}]
    // e.g. Flattening [1,2,3,4] with axis 2 yields [2,12].
    uint32_t coercedSizes[2];
    if (dimensions.size() > 1 && coerceAxis < gsl::narrow_cast<uint32_t>(dimensions.size()))
    {
        uint32_t dimension0 = 1u;
        uint32_t dimension1 = dimensions[coerceAxis];

        for (uint32_t i = 0; i < coerceAxis; ++i)
        {
            dimension0 *= dimensions[i];
        }

        for (size_t i = coerceAxis + 1, ci = dimensions.size(); i < ci; ++i)
        {
            dimension1 *= dimensions[i];
        }

        coercedSizes[0] = dimension0;
        coercedSizes[1] = dimension1;

        sizes = coercedSizes;
    }
    else
    {
        sizes = dimensions;
    }

    // Determine the number of dimensions that should be aligned to the left edge when promoting to the minimum dimension count.
    // Negative values mean align from the right.
    const int32_t rank = gsl::narrow_cast<int32_t>(sizes.size());
    leftAlignedDimensionCount = leftAlignedDimensionCount < 0 ? std::max(0, leftAlignedDimensionCount + rank) : std::min(rank, leftAlignedDimensionCount);

    ML_CHECK_VALID_ARGUMENT(rank <= MaximumDimensionCount);
    m_bufferTensorDesc.DimensionCount = std::max(rank, int32_t(minDimensionCount));

    // Many DirectML operators accept only certain dimension counts, but it's very common for ONNX models
    // to have fewer dimensions than that. So this logic massages the dimension count up to what is needed
    // by filling unused dimensions with size 1, by left-aligning, right-aligning, or even mid-filling.
    //
    // e.g.:
    //
    //      elementwise addition - [H W]   -> [1 1 H W], leftAlignedCount = 0, placement = 0
    //      1D convolution       - [N C W] -> [N C 1 W], leftAlignedCount = 2, placement = 0
    //      batch normalization  - [C]     -> [1 C 1 1], leftAlignedCount = 1, placement = 1
    //
    {
        // Compute the total number of additional dimensions to fill with 1's,
        // before, after, and in the middle.
        const int32_t totalFillerCount     = m_bufferTensorDesc.DimensionCount - rank;
        const int32_t leadingFillerCount   = std::clamp(placement, 0, totalFillerCount);
        const int32_t remainingFillerCount = totalFillerCount - leadingFillerCount;
        const int32_t trailingFillerCount  = std::clamp(-placement, 0, remainingFillerCount);
        const int32_t middleFillerCount    = remainingFillerCount - trailingFillerCount;
        const int32_t firstRightAlignedDim = leadingFillerCount + leftAlignedDimensionCount + middleFillerCount;

        int i = 0, j = 0;
        while (j < leadingFillerCount)          { m_sizes[j++] = 1; }
        while (i < leftAlignedDimensionCount)   { m_sizes[j++] = sizes[i++]; }
        while (j < firstRightAlignedDim)        { m_sizes[j++] = 1; }
        while (i < rank)                        { m_sizes[j++] = sizes[i++]; }
        while (j < MaximumDimensionCount)       { m_sizes[j++] = 1; }
    }

    // By default, assume strides are not necessary.
    bool useStrides = false;

    if (dimensions != nonBroadcastDimensions)
    {
        // If broadcasting is used, then strides are used.
        useStrides = true;

        // Walk backwards through both input shapes and broadcast or default each dimension
        auto nonBroadcastDimsIter = nonBroadcastDimensions.rbegin();
        uint32_t elementCount = 1;
        for (int descDimIndex = m_bufferTensorDesc.DimensionCount - 1; descDimIndex >= 0; --descDimIndex)
        {
            if (nonBroadcastDimsIter == nonBroadcastDimensions.rend() || (*nonBroadcastDimsIter == 1))
            {
                m_strides[descDimIndex] = 0;
            }
            else
            {
                m_strides[descDimIndex] = elementCount;
                elementCount *= (*nonBroadcastDimsIter);
            }

            if (nonBroadcastDimsIter != nonBroadcastDimensions.rend())
            {
                ++nonBroadcastDimsIter;
            }
        }
    }

    uint64_t endPaddingInBytes = 0;

    if (dataType == MLOperatorTensorDataType::UInt64 || dataType == MLOperatorTensorDataType::Int64)
    {
        // DirectML doesn't support tensor of int64 because Direct3D doesn't support
        // the data type. A workaround is to use strides to fake 64-bit memory access
        // while only the lower 32 bits contains the data. This trick obviously doesn't
        // work if the data element is genuine 64-bit. It also doesn't work if the data
        // element is negative as the signed bit will be incorrectly interpreted.
        m_bufferTensorDesc.DataType = DML_TENSOR_DATA_TYPE_UINT32;

        // If the strides haven't been calculated yet, initialize them as packed.
        if (!useStrides)
        {
            uint32_t stride = 1;
            for (int i = m_bufferTensorDesc.DimensionCount - 1; i >= 0; i--)
            {
                m_strides[i] = stride;
                stride *= m_sizes[i];
            }
        }

        // Double the stride values to emulate 64-bit integer support.
        for (uint32_t i = 0; i < m_bufferTensorDesc.DimensionCount; ++i)
        {
            m_strides[i] *= 2;
        }

        useStrides = true;

        // The physical size of the tensor will have an extra 4 bytes at the end.
        // DMLCalcBufferTensorSize calculates the minimum implied size, which is based on the last
        // addressable element of the tensor plus the space for the last element. However, the size
        // of the last element is now halved from 8 bytes to 4 bytes.
        //
        // Example:
        // Original Tensor: size={2,3}, strides={3,1}, type=int64, size = (1+{1,2}*{3,1})*sizeof(int64) = 6 * 8 = 48
        // Emulated Tensor: size={2,3}, strides={6,2}, type=int32, size = (1+{1,2}*{6,2})*sizeof(int32) = 11 * 4 = 44
        //
        // DirectML itself won't read/write the last 4 bytes, but we want the total size to be accurate
        // so that the entire region can be zeroed.
        endPaddingInBytes = sizeof(uint32_t);
    }

    if (useStrides)
    {
        m_bufferTensorDesc.Strides = m_strides;
    }

    m_bufferTensorDesc.Flags = DML_TENSOR_FLAG_NONE;
    m_bufferTensorDesc.GuaranteedBaseOffsetAlignment = guaranteedBaseOffsetAlignment;
    m_bufferTensorDesc.TotalTensorSizeInBytes = DMLCalcBufferTensorSize(
        m_bufferTensorDesc.DataType,
        m_bufferTensorDesc.DimensionCount,
        m_sizes,
        useStrides ? m_strides : nullptr
        ) + endPaddingInBytes;
}

gsl::span<const uint32_t> TensorDesc::GetStrides() const
{
    if (m_bufferTensorDesc.Strides == nullptr)
    {
        return {};
    }
    return { m_strides, m_strides + m_bufferTensorDesc.DimensionCount };
}

DML_TENSOR_DESC TensorDesc::GetDmlDesc()
{
    if (m_tensorType == DML_TENSOR_TYPE_INVALID)
    {
        return { m_tensorType, nullptr };
    }

    m_bufferTensorDesc.Sizes = m_sizes;
    if (m_bufferTensorDesc.Strides)
    {
        m_bufferTensorDesc.Strides = m_strides;
    }

    // Only buffer tensors are supported right now.
    assert(m_tensorType == DML_TENSOR_TYPE_BUFFER);
    return { m_tensorType, &m_bufferTensorDesc };
}

// ONNX likes to use signed types for logically unsigned index data.  DML avoids this inconsistency and therefore
// requires coercion by the caller.
void TensorDesc::ForceUnsignedDataType()
{
    static_assert(ApiTraits::EnumValueCount<DML_TENSOR_DATA_TYPE> == 9, "New tensor data type.  Update cases.");

    switch (m_bufferTensorDesc.DataType)
    {
    case DML_TENSOR_DATA_TYPE_INT32:
        m_bufferTensorDesc.DataType = DML_TENSOR_DATA_TYPE_UINT32;
        break;

    case DML_TENSOR_DATA_TYPE_INT16:
        m_bufferTensorDesc.DataType = DML_TENSOR_DATA_TYPE_UINT16;
        break;

    case DML_TENSOR_DATA_TYPE_INT8:
        m_bufferTensorDesc.DataType = DML_TENSOR_DATA_TYPE_UINT8;
        break;

        // Nothing to do if already unsigned
    case DML_TENSOR_DATA_TYPE_UINT32:
    case DML_TENSOR_DATA_TYPE_UINT16:
    case DML_TENSOR_DATA_TYPE_UINT8:
        break;

    default:
        ML_INVALID_ARGUMENT("Can't coerce unknown or non-integral data type");
    }
}
<commit_msg>TensorDesc::Placement test failure - cherry pick Vibranium fix. (#2328)<commit_after>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "precomp.h"

using namespace Dml;

TensorDesc::TensorDesc(
    DML_TENSOR_DATA_TYPE dataType,
    gsl::span<const uint32_t> sizes,
    std::optional<gsl::span<const uint32_t>> strides,
    uint32_t guaranteedBaseOffsetAlignment
    )
{
    m_tensorType = DML_TENSOR_TYPE_BUFFER;
    m_bufferTensorDesc.DataType = dataType;
    m_mlOperatorTensorDataType = GetMlDataTypeFromDmlDataType(dataType);

    ML_CHECK_VALID_ARGUMENT(gsl::narrow_cast<size_t>(sizes.size()) <= std::size(m_sizes));
    std::copy(sizes.begin(), sizes.end(), m_sizes);
    m_bufferTensorDesc.Sizes = m_sizes;

    if (strides)
    {
        ML_CHECK_VALID_ARGUMENT(strides->size() == sizes.size());
        std::copy(strides->begin(), strides->end(), m_strides);
        m_bufferTensorDesc.Strides = m_strides;
    }

    m_bufferTensorDesc.DimensionCount = gsl::narrow_cast<uint32_t>(sizes.size());
    m_bufferTensorDesc.Flags = DML_TENSOR_FLAG_NONE;

    m_bufferTensorDesc.GuaranteedBaseOffsetAlignment = guaranteedBaseOffsetAlignment;
    m_bufferTensorDesc.TotalTensorSizeInBytes = DMLCalcBufferTensorSize(
        m_bufferTensorDesc.DataType,
        m_bufferTensorDesc.DimensionCount,
        m_sizes,
        strides ? m_strides : nullptr
        );
}

TensorDesc::TensorDesc(MLOperatorTensorDataType dataType)
{
    m_mlOperatorTensorDataType = dataType;
    m_bufferTensorDesc.DataType = GetDmlDataTypeFromMlDataType(dataType);
    // Leave all other fields deferred, including m_tensorType = DML_TENSOR_TYPE_INVALID.
}

TensorDesc::TensorDesc(
    MLOperatorTensorDataType dataType,
    gsl::span<const uint32_t> dimensions, // Desired dimensions
    gsl::span<const uint32_t> nonBroadcastDimensions, // Actual physical dimensions
    uint32_t coerceAxis,
    int32_t placement, // Adjustment offset of the passed dimensions within the minDimensionCount.
    int32_t leftAlignedDimensionCount, // Number of dimensions that remain left aligned when expanded to minimum count (INT32_MAX means all, 0 means all right aligned).
    uint32_t minDimensionCount,
    uint32_t guaranteedBaseOffsetAlignment
    )
{
    m_tensorType = DML_TENSOR_TYPE_BUFFER;
    m_mlOperatorTensorDataType = dataType;

    m_bufferTensorDesc.DataType = GetDmlDataTypeFromMlDataType(dataType);
    ML_CHECK_VALID_ARGUMENT(ApiTraits::IsValidEnumValue(m_bufferTensorDesc.DataType));

    gsl::span<const uint32_t> sizes;

    // If needed, flatten the tensor dimensions to a 2D tensor of size [a_0 * ... * a_{coerceAxis-1}, a_{coerceAxis} * ... * a_{n-1}]
    // e.g. Flattening [1,2,3,4] with axis 2 yields [2,12].
    uint32_t coercedSizes[2];
    if (dimensions.size() > 1 && coerceAxis < gsl::narrow_cast<uint32_t>(dimensions.size()))
    {
        uint32_t dimension0 = 1u;
        uint32_t dimension1 = dimensions[coerceAxis];

        for (uint32_t i = 0; i < coerceAxis; ++i)
        {
            dimension0 *= dimensions[i];
        }

        for (size_t i = coerceAxis + 1, ci = dimensions.size(); i < ci; ++i)
        {
            dimension1 *= dimensions[i];
        }

        coercedSizes[0] = dimension0;
        coercedSizes[1] = dimension1;

        sizes = coercedSizes;
    }
    else
    {
        sizes = dimensions;
    }

    ////////////////////////////////////////
    // Align dimensions

    // Determine the number of dimensions that should be aligned to the left edge when promoting to the minimum dimension count.
    // Negative values mean align from the right.
    const int32_t rank = gsl::narrow_cast<int32_t>(sizes.size());
    leftAlignedDimensionCount = leftAlignedDimensionCount < 0 ? std::max(0, leftAlignedDimensionCount + rank) : std::min(rank, leftAlignedDimensionCount);

    ML_CHECK_VALID_ARGUMENT(rank <= MaximumDimensionCount);
    m_bufferTensorDesc.DimensionCount = std::max(rank, int32_t(minDimensionCount));

    // Many DirectML operators accept only certain dimension counts, but it's very common for ONNX models
    // to have fewer dimensions than that. So this logic massages the dimension count up to what is needed
    // by filling unused dimensions with size 1, by left-aligning, right-aligning, or even mid-filling.
    //
    // e.g.:
    //
    //      elementwise addition - [H W]   -> [1 1 H W], leftAlignedCount = 0, placement = 0
    //      1D convolution       - [N C W] -> [N C 1 W], leftAlignedCount = 2, placement = 0
    //      batch normalization  - [C]     -> [1 C 1 1], leftAlignedCount = 1, placement = 1
    //
    {
        // Compute the total number of additional dimensions to fill with 1's,
        // before, after, and in the middle.
        const int32_t totalFillerCount     = m_bufferTensorDesc.DimensionCount - rank;
        const int32_t leadingFillerCount   = std::clamp(placement, 0, totalFillerCount);
        const int32_t remainingFillerCount = totalFillerCount - leadingFillerCount;
        const int32_t trailingFillerCount  = std::clamp(-placement, 0, remainingFillerCount);
        const int32_t middleFillerCount    = remainingFillerCount - trailingFillerCount;
        const int32_t firstRightAlignedDim = leadingFillerCount + leftAlignedDimensionCount + middleFillerCount;

        int i = 0, j = 0;
        while (j < leadingFillerCount)          { m_sizes[j++] = 1; }
        while (i < leftAlignedDimensionCount)   { m_sizes[j++] = sizes[i++]; }
        while (j < firstRightAlignedDim)        { m_sizes[j++] = 1; }
        while (i < rank)                        { m_sizes[j++] = sizes[i++]; }
        while (j < MaximumDimensionCount)       { m_sizes[j++] = 1; }
    }

    ////////////////////////////////////////
    // Coerce the physical shape to the desired shape.

    // By default, assume strides are not necessary.
    bool useStrides = false;

    if (dimensions != nonBroadcastDimensions)
    {
        // This broadcasting and subset logic is only applicable to the simple case where all
        // dimensions are contiguously right aligned, which means no flattening coercion,
        // placement offset, or split alignment. In such cases, the right side of m_sizes
        // should match the original dimensions.
        ML_CHECK_VALID_ARGUMENT(std::equal(
            dimensions.begin(),
            dimensions.end(),
            &m_sizes[m_bufferTensorDesc.DimensionCount - rank],
            &m_sizes[m_bufferTensorDesc.DimensionCount]
        ));

        // Stretch any dimensions with a single element.
        //
        // e.g. physical [2,1,4]
        //       desired [2,3,4]
        //       output  [2,3,4]
        //       strides [4,0,1]
        //
        // If broadcasting is used, then strides are used.
        useStrides = true;

        // Walk backwards through both input shapes and broadcast or default each dimension.
        auto nonBroadcastDimsIter = nonBroadcastDimensions.rbegin();
        uint32_t elementCount = 1;

        for (int descDimIndex = m_bufferTensorDesc.DimensionCount - 1; descDimIndex >= 0; --descDimIndex)
        {
            if (nonBroadcastDimsIter == nonBroadcastDimensions.rend() || (*nonBroadcastDimsIter == 1))
            {
                m_strides[descDimIndex] = 0;
            }
            else
            {
                m_strides[descDimIndex] = elementCount;
                elementCount *= (*nonBroadcastDimsIter);
            }

            if (nonBroadcastDimsIter != nonBroadcastDimensions.rend())
            {
                ++nonBroadcastDimsIter;
            }
        }
    }

    ////////////////////////////////////////
    // Handle 64-bit tensors.

    uint64_t endPaddingInBytes = 0;

    if (dataType == MLOperatorTensorDataType::UInt64 || dataType == MLOperatorTensorDataType::Int64)
    {
        // DirectML doesn't support tensor of int64 because Direct3D doesn't support
        // the data type. A workaround is to use strides to fake 64-bit memory access
        // while only the lower 32 bits contains the data. This trick obviously doesn't
        // work if the data element is genuine 64-bit. It also doesn't work if the data
        // element is negative as the signed bit will be incorrectly interpreted.
        m_bufferTensorDesc.DataType = DML_TENSOR_DATA_TYPE_UINT32;

        // If the strides haven't been calculated yet, initialize them as packed.
        if (!useStrides)
        {
            uint32_t stride = 1;
            for (int i = m_bufferTensorDesc.DimensionCount - 1; i >= 0; i--)
            {
                m_strides[i] = stride;
                stride *= m_sizes[i];
            }
        }

        // Double the stride values to emulate 64-bit integer support.
        for (uint32_t i = 0; i < m_bufferTensorDesc.DimensionCount; ++i)
        {
            m_strides[i] *= 2;
        }

        useStrides = true;

        // The physical size of the tensor will have an extra 4 bytes at the end.
        // DMLCalcBufferTensorSize calculates the minimum implied size, which is based on the last
        // addressable element of the tensor plus the space for the last element. However, the size
        // of the last element is now halved from 8 bytes to 4 bytes.
        //
        // Example:
        // Original Tensor: size={2,3}, strides={3,1}, type=int64, size = (1+{1,2}*{3,1})*sizeof(int64) = 6 * 8 = 48
        // Emulated Tensor: size={2,3}, strides={6,2}, type=int32, size = (1+{1,2}*{6,2})*sizeof(int32) = 11 * 4 = 44
        //
        // DirectML itself won't read/write the last 4 bytes, but we want the total size to be accurate
        // so that the entire region can be zeroed.
        endPaddingInBytes = sizeof(uint32_t);
    }

    if (useStrides)
    {
        m_bufferTensorDesc.Strides = m_strides;
    }

    m_bufferTensorDesc.Flags = DML_TENSOR_FLAG_NONE;
    m_bufferTensorDesc.GuaranteedBaseOffsetAlignment = guaranteedBaseOffsetAlignment;
    m_bufferTensorDesc.TotalTensorSizeInBytes = DMLCalcBufferTensorSize(
        m_bufferTensorDesc.DataType,
        m_bufferTensorDesc.DimensionCount,
        m_sizes,
        useStrides ? m_strides : nullptr
        ) + endPaddingInBytes;
}

gsl::span<const uint32_t> TensorDesc::GetStrides() const
{
    if (m_bufferTensorDesc.Strides == nullptr)
    {
        return {};
    }
    return { m_strides, m_strides + m_bufferTensorDesc.DimensionCount };
}

DML_TENSOR_DESC TensorDesc::GetDmlDesc()
{
    if (m_tensorType == DML_TENSOR_TYPE_INVALID)
    {
        return { m_tensorType, nullptr };
    }

    m_bufferTensorDesc.Sizes = m_sizes;
    if (m_bufferTensorDesc.Strides)
    {
        m_bufferTensorDesc.Strides = m_strides;
    }

    // Only buffer tensors are supported right now.
    assert(m_tensorType == DML_TENSOR_TYPE_BUFFER);
    return { m_tensorType, &m_bufferTensorDesc };
}

// ONNX likes to use signed types for logically unsigned index data.  DML avoids this inconsistency and therefore
// requires coercion by the caller.
void TensorDesc::ForceUnsignedDataType()
{
    static_assert(ApiTraits::EnumValueCount<DML_TENSOR_DATA_TYPE> == 9, "New tensor data type.  Update cases.");

    switch (m_bufferTensorDesc.DataType)
    {
    case DML_TENSOR_DATA_TYPE_INT32:
        m_bufferTensorDesc.DataType = DML_TENSOR_DATA_TYPE_UINT32;
        break;

    case DML_TENSOR_DATA_TYPE_INT16:
        m_bufferTensorDesc.DataType = DML_TENSOR_DATA_TYPE_UINT16;
        break;

    case DML_TENSOR_DATA_TYPE_INT8:
        m_bufferTensorDesc.DataType = DML_TENSOR_DATA_TYPE_UINT8;
        break;

        // Nothing to do if already unsigned
    case DML_TENSOR_DATA_TYPE_UINT32:
    case DML_TENSOR_DATA_TYPE_UINT16:
    case DML_TENSOR_DATA_TYPE_UINT8:
        break;

    default:
        ML_INVALID_ARGUMENT("Can't coerce unknown or non-integral data type");
    }
}
<|endoftext|>


<commit_before>// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
//
// Copyright 2015 Heiko Fink, All Rights Reserved.
//
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
//
// Perception Neuron (TM) is a trademark of Beijing Noitom Technology Ltd.
//
// Description:
// This code implements the Controller functions that are used to connect to the Perception Neuron (TM) Axis Player.
//

#include "ThirdPersonNeuron.h"
#include "ThirdPersonNeuronController.h"

// Sets default values
AThirdPersonNeuronController::AThirdPersonNeuronController()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AThirdPersonNeuronController::BeginPlay()
{
	Super::BeginPlay();

}

// Called every frame
void AThirdPersonNeuronController::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// Read each tick a new motionline. Additionally motionlines are just discarded.
	if (bConnected == true)
	{
		uint32 BytesPending = 0;

		if (ReceiverSocket->HasPendingData(BytesPending) == true)
		{
#define SIZEOFDATA 10000
			uint8 Data[SIZEOFDATA];
			int32 BytesRead = 0;
			bool bMotionLineBeginFound = false;
			bool bMotionLineEndFound = false;

			if (ReceiverSocket->Recv(Data, SIZEOFDATA, BytesRead) == true)
			{
				int32 i, j, k;

				if (MotionLineFormat == Neuron)
				{
					// Scan for the beginning of a motion line and synchronize to Avatarname
					// Neuron BVH output format:
					// 0 Avatarname 0.00 0.00 ... 0.00 ||
					for (i = j = k = 0; i < BytesRead - 2; i++)
					{
						if ((Data[i] == '0') && (Data[i + 1] == ' ') && ((Data[i + 2] < '0') || (Data[i + 2] > '9') || (Data[i + 2] == '-')))
						{
							bMotionLineBeginFound = true;
							// Skip Avatarname
							for (j = i + 2; j < BytesRead; j++)
							{
								if (Data[j] == ' ')
									break;
							}
							break;
						}
					}
					if (bMotionLineBeginFound == true)
					{
						// Scan for the end of the motion line
						for (k = j; k < BytesRead; k++)
						{
							if ((Data[k] == '|') || (Data[k] == '\n') || (Data[k] == '\r'))
							{
								bMotionLineEndFound = true;
								break;
							}
						}
					}
				}
				else
				{
					// Just synchronize to first float and check if floatcount matches bonecount else try next line
					// Standard BVH format:
					// 0.00 0.00 ... 0.00
					i = j = k = 0;
					for (; i < BytesRead - 1;)
					{
						for (; i < BytesRead; i++)
						{
							if ((Data[i] >= '0') && (Data[i] <= '9') || (Data[i] == '-') || (Data[i] == '.'))
							{
								j = i;
								bMotionLineBeginFound = true;
								break;
							}
						}
						if (bMotionLineBeginFound == true)
						{
							int32 t = 0;
							bMotionLineEndFound = false;
							// Scan for the end of the motion line and count empty spaces between floats
							for (i = j; i < BytesRead - 1; i++)
							{
								if (((Data[i] == ' ') || (Data[i] == '\t')) && (((Data[i + 1] >= '0') && (Data[i + 1] <= '9')) || (Data[i + 1] == '-') || (Data[i + 1] == '.')))
									t++;
								if ((Data[i] == '\n') || (Data[i] == '\r'))
								{
									bMotionLineEndFound = true;
									break;
								}
							}
							if (bMotionLineEndFound)
							{
								int32 FloatsPerBone = 6;	 // 3 for x,y,z translation and 3 for x,y,z rotation
								int32 FloatsPerReference = 6; // 3 for x,y,z translation and 3 for x,y,z rotation

								if (bDisplacement == false)
									FloatsPerBone = 3;	// If there is no displacement (translation) info we have only 3 floats for rotation left
								if (bReference == false)
									FloatsPerReference = 0;
								// Check if empty spaces matches bone count
								if (t == ((BoneNr * FloatsPerBone) + FloatsPerReference - 1))
								{
									k = i;
									break;
								}
							}
						}
					}
				}

				if (bMotionLineEndFound == true)
				{
					// We have now a valid motion line captured between j and k

					// Forward to first value
					for (i = j; i < k; i++)
						if ((Data[i] >= '0') && (Data[i] <= '9') || (Data[i] == '-') || (Data[i] == '.'))
							break;

					int32 m = 0;
					// Get all float values from motion line
					for (int32 f = 0; f < MAXFLOATS && i < k; f++)
					{
						// Read ASCII float value into float array
						if (f >= FloatSkip)
						{
							MotionLine[m] = atof((char *)&Data[i]);
							m++;
						}
						// Forward to end of value we read
						for (; i < k; i++)
							if (((Data[i] < '0') || (Data[i] > '9')) && (Data[i] != '-') && (Data[i] != '.'))
								break;

						// Forward to next value
						for (; i < k; i++)
						{
							// Sanitycheck for line ending
							if ((Data[i] == '|') || (Data[i] == '\n') || (Data[i] == '\r'))
							{
								i = k; // Stop scanning
								break;
							}
							if ((Data[i] >= '0') && (Data[i] <= '9') || (Data[i] == '-') || (Data[i] == '.'))
								break;
						}
					}
					FloatCount = m;
				} // End bMotionLineEndFound

				// If we get more data then we can process per tick, read socket till no more data is left and ignore it
				while (ReceiverSocket->HasPendingData(BytesPending))
				{
					ReceiverSocket->Recv(Data, SIZEOFDATA, BytesRead);
					// if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Data skipped: %u"), BytesRead));
				}
			} // End Recv
		} // End HasPendingData
	} // End bConnected
}

bool AThirdPersonNeuronController::ParseBVHFile(FString BVHFileName)
{
	// Load BVH file
	TArray<FString> Lines;
	if (FFileHelper::LoadANSITextFileToStrings(*(FPaths::GameDir() + FString("Content/") + BVHFileName), NULL, Lines) != true)
	{
		if (GEngine)
		{
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Could not load BVH file:%s"), *(FPaths::GameDir() + FString("Content/") + BVHFileName)));
		}
		return false;
	}

	// Parse BVH file and get bone names, offsets and channels
	int32 bone = 0;
	bool  bToggle = false;

	for (int32 i = 0; i < Lines.Num(); i++)
	{
		Lines[i].Trim();
		if ((Lines[i].StartsWith(TEXT("ROOT"), ESearchCase::IgnoreCase) == true) ||
			(Lines[i].StartsWith(TEXT("JOINT"), ESearchCase::IgnoreCase) == true))
		{
			TArray<FString> Words;
			if (Lines[i].ParseIntoArray(Words, TEXT(" "), false) >= 2)
			{
				Skeleton[bone].Name = Words[1];
				bToggle = true;
			}
		}
		else if (Lines[i].StartsWith(TEXT("OFFSET"), ESearchCase::IgnoreCase) == true)
		{
			if (bToggle == true)	// Ignore additional offsets from "End Site"
			{
				TArray<FString> Words;
				if (Lines[i].ParseIntoArray(Words, TEXT(" "), false) >= 4)
				{
					Skeleton[bone].Offset[0] = FCString::Atof(*Words[1]);
					Skeleton[bone].Offset[1] = FCString::Atof(*Words[2]);
					Skeleton[bone].Offset[2] = FCString::Atof(*Words[3]);
					bToggle = false;
				}
			}
		}
		else if (Lines[i].StartsWith(TEXT("CHANNELS"), ESearchCase::IgnoreCase) == true)
		{
			TArray<FString> Words;
			if (Lines[i].ParseIntoArray(Words, TEXT(" "), false) >= 4)
			{
				Skeleton[bone].ChannelCount = FCString::Atoi(*Words[1]);
				if (Skeleton[bone].ChannelCount != 6)
				{
					if (GEngine)
					{
						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Channelcount must be 6 on bone:%u"), bone));
					}
					return false;
				}
				Skeleton[bone].XPos = Skeleton[bone].YPos = Skeleton[bone].ZPos = 0;
				Skeleton[bone].XRot = Skeleton[bone].YRot = Skeleton[bone].ZRot = 0;
				for (int32 j = 0; j < Skeleton[bone].ChannelCount; j++)
				{
					// Detect channel order
					// E.g.: Xposition Yposition Zposition Xrotation Yrotation Zrotation
					if (Words[j + 2].StartsWith(TEXT("Xposition"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].XPos = j;
					else if (Words[j + 2].StartsWith(TEXT("Yposition"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].YPos = j;
					else if (Words[j + 2].StartsWith(TEXT("Zposition"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].ZPos = j;
					else if (Words[j + 2].StartsWith(TEXT("Xrotation"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].XRot = j;
					else if (Words[j + 2].StartsWith(TEXT("Yrotation"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].YRot = j;
					else if (Words[j + 2].StartsWith(TEXT("Zrotation"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].ZRot = j;
				}
				// Check if we support rotation order
				if ((Skeleton[bone].XRot < Skeleton[bone].YRot) && (Skeleton[bone].YRot < Skeleton[bone].ZRot)) // e.g. 123
					Skeleton[bone].RotOrder = XYZ;
				else if ((Skeleton[bone].ZRot < Skeleton[bone].XRot) && (Skeleton[bone].XRot < Skeleton[bone].YRot)) // e.g. 312
					Skeleton[bone].RotOrder = ZXY;
				else if ((Skeleton[bone].YRot < Skeleton[bone].XRot) && (Skeleton[bone].XRot < Skeleton[bone].ZRot)) // e.g. 213
					Skeleton[bone].RotOrder = YXZ;
				else
				{
					if (GEngine)
					{
						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Rotation order not supported on bone:%u"), bone));
					}
					return false;
				}

				if (bone >= MAXBONES)
				{
					if (GEngine)
					{
						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Too much bones in BVH file:%u"), bone));
					}
					return false;
				}
				bone++;
			}
		}
	} // end of for

	BoneNr = bone;

	return true;
}

// Connect to BVH server (for e.g. Axis Neuron SW)
bool AThirdPersonNeuronController::Connect(FString HostName, int32 Port)
{
	if (bConnected == true)
		return false;

	// Set up reference bone handling
	// Template does not support transition for the reference bone yet
	// Should be no problem, because normally reference bone does not change values.
	if (bReference == true)
	{
		// Skip reference bone x,y,z translation and x,y,z rotation
		// regardless if displacement is active or not (Axis Neuron sends always 6 floats)
		FloatSkip = 6;
	}

	// Create TCP Socket and connect
	ISocketSubsystem* const SocketSubSystem = ISocketSubsystem::Get();
	if (SocketSubSystem)
	{
		ReceiverSocket = SocketSubSystem->CreateSocket(NAME_Stream, TEXT("PerceptionNeuronSocket"), false);
		if (ReceiverSocket == NULL)
			return false;

		auto ResolveInfo = SocketSubSystem->GetHostByName(TCHAR_TO_ANSI(*HostName));
		while (!ResolveInfo->IsComplete());

		if (ResolveInfo->GetErrorCode() == 0)
		{
			const FInternetAddr* Addr = &ResolveInfo->GetResolvedAddress();
			uint32 IP;
			Addr->GetIp(IP);

			TSharedRef<FInternetAddr> InetAddr = SocketSubSystem->CreateInternetAddr();
			InetAddr->SetIp(IP);
			InetAddr->SetPort(Port);

			bConnected = ReceiverSocket->Connect(*InetAddr);
		}
	}

	return bConnected;
}

// Called when the game stops
void AThirdPersonNeuronController::BeginDestroy()
{
	Super::BeginDestroy();

	Disconnect();
}

// Disconnect from BVH server
void AThirdPersonNeuronController::Disconnect(void)
{
	if (bConnected == true)
	{
		bConnected = false;
		ReceiverSocket->Close();
	}
}

<commit_msg>Fix a line ending bug in BVH standard format handling<commit_after>// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
//
// Copyright 2015 Heiko Fink, All Rights Reserved.
//
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
//
// Perception Neuron (TM) is a trademark of Beijing Noitom Technology Ltd.
//
// Description:
// This code implements the Controller functions that are used to connect to the Perception Neuron (TM) Axis Player.
//

#include "ThirdPersonNeuron.h"
#include "ThirdPersonNeuronController.h"

// Sets default values
AThirdPersonNeuronController::AThirdPersonNeuronController()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AThirdPersonNeuronController::BeginPlay()
{
	Super::BeginPlay();

}

// Called every frame
void AThirdPersonNeuronController::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// Read each tick a new motionline. Additionally motionlines are just discarded.
	if (bConnected == true)
	{
		uint32 BytesPending = 0;

		if (ReceiverSocket->HasPendingData(BytesPending) == true)
		{
#define SIZEOFDATA 10000
			uint8 Data[SIZEOFDATA];
			int32 BytesRead = 0;
			bool bMotionLineBeginFound = false;
			bool bMotionLineEndFound = false;

			if (ReceiverSocket->Recv(Data, SIZEOFDATA, BytesRead) == true)
			{
				int32 i, j, k;

				if (MotionLineFormat == Neuron)
				{
					// Scan for the beginning of a motion line and synchronize to Avatarname
					// Neuron BVH output format:
					// 0 Avatarname 0.00 0.00 ... 0.00 ||
					for (i = j = k = 0; i < BytesRead - 2; i++)
					{
						if ((Data[i] == '0') && (Data[i + 1] == ' ') && ((Data[i + 2] < '0') || (Data[i + 2] > '9') || (Data[i + 2] == '-')))
						{
							bMotionLineBeginFound = true;
							// Skip Avatarname
							for (j = i + 2; j < BytesRead; j++)
							{
								if (Data[j] == ' ')
									break;
							}
							break;
						}
					}
					if (bMotionLineBeginFound == true)
					{
						// Scan for the end of the motion line
						for (k = j; k < BytesRead; k++)
						{
							if ((Data[k] == '|') || (Data[k] == '\n') || (Data[k] == '\r'))
							{
								bMotionLineEndFound = true;
								break;
							}
						}
					}
				}
				else
				{
					// Just synchronize to first float and check if floatcount matches bonecount else try next line
					// Standard BVH format:
					// 0.00 0.00 ... 0.00
					i = j = k = 0;
					for (; i < BytesRead - 1;)
					{
						for (; i < BytesRead; i++)
						{
							if ((Data[i] >= '0') && (Data[i] <= '9') || (Data[i] == '-') || (Data[i] == '.'))
							{
								j = i;
								bMotionLineBeginFound = true;
								break;
							}
						}
						if (bMotionLineBeginFound == true)
						{
							int32 t = 0;
							bMotionLineEndFound = false;
							// Scan for the end of the motion line and count empty spaces between floats
							for (i = j; i < BytesRead; i++)
							{
								if (i < (BytesRead - 1))
									if (((Data[i] == ' ') || (Data[i] == '\t')) && (((Data[i + 1] >= '0') && (Data[i + 1] <= '9')) || (Data[i + 1] == '-') || (Data[i + 1] == '.')))
										t++;
								if ((Data[i] == '\n') || (Data[i] == '\r'))
								{
									bMotionLineEndFound = true;
									break;
								}
							}
							if (bMotionLineEndFound)
							{
								int32 FloatsPerBone = 6;	 // 3 for x,y,z translation and 3 for x,y,z rotation
								int32 FloatsPerReference = 6; // 3 for x,y,z translation and 3 for x,y,z rotation

								if (bDisplacement == false)
									FloatsPerBone = 3;	// If there is no displacement (translation) info we have only 3 floats for rotation left
								if (bReference == false)
									FloatsPerReference = 0;
								// Check if empty spaces matches bone count
								if (t == ((BoneNr * FloatsPerBone) + FloatsPerReference - 1))
								{
									k = i;
									break;
								}
							}
						}
					}
				}

				if (bMotionLineEndFound == true)
				{
					// We have now a valid motion line captured between j and k

					// Forward to first value
					for (i = j; i < k; i++)
						if ((Data[i] >= '0') && (Data[i] <= '9') || (Data[i] == '-') || (Data[i] == '.'))
							break;

					int32 m = 0;
					// Get all float values from motion line
					for (int32 f = 0; f < MAXFLOATS && i < k; f++)
					{
						// Read ASCII float value into float array
						if (f >= FloatSkip)
						{
							MotionLine[m] = atof((char *)&Data[i]);
							m++;
						}
						// Forward to end of value we read
						for (; i < k; i++)
							if (((Data[i] < '0') || (Data[i] > '9')) && (Data[i] != '-') && (Data[i] != '.'))
								break;

						// Forward to next value
						for (; i < k; i++)
						{
							// Sanitycheck for line ending
							if ((Data[i] == '|') || (Data[i] == '\n') || (Data[i] == '\r'))
							{
								i = k; // Stop scanning
								break;
							}
							if ((Data[i] >= '0') && (Data[i] <= '9') || (Data[i] == '-') || (Data[i] == '.'))
								break;
						}
					}
					FloatCount = m;
				} // End bMotionLineEndFound

				// If we get more data then we can process per tick, read socket till no more data is left and ignore it
				while (ReceiverSocket->HasPendingData(BytesPending))
				{
					ReceiverSocket->Recv(Data, SIZEOFDATA, BytesRead);
					// if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Data skipped: %u"), BytesRead));
				}
			} // End Recv
		} // End HasPendingData
	} // End bConnected
}

bool AThirdPersonNeuronController::ParseBVHFile(FString BVHFileName)
{
	// Load BVH file
	TArray<FString> Lines;
	if (FFileHelper::LoadANSITextFileToStrings(*(FPaths::GameDir() + FString("Content/") + BVHFileName), NULL, Lines) != true)
	{
		if (GEngine)
		{
			GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Could not load BVH file:%s"), *(FPaths::GameDir() + FString("Content/") + BVHFileName)));
		}
		return false;
	}

	// Parse BVH file and get bone names, offsets and channels
	int32 bone = 0;
	bool  bToggle = false;

	for (int32 i = 0; i < Lines.Num(); i++)
	{
		Lines[i].Trim();
		if ((Lines[i].StartsWith(TEXT("ROOT"), ESearchCase::IgnoreCase) == true) ||
			(Lines[i].StartsWith(TEXT("JOINT"), ESearchCase::IgnoreCase) == true))
		{
			TArray<FString> Words;
			if (Lines[i].ParseIntoArray(Words, TEXT(" "), false) >= 2)
			{
				Skeleton[bone].Name = Words[1];
				bToggle = true;
			}
		}
		else if (Lines[i].StartsWith(TEXT("OFFSET"), ESearchCase::IgnoreCase) == true)
		{
			if (bToggle == true)	// Ignore additional offsets from "End Site"
			{
				TArray<FString> Words;
				if (Lines[i].ParseIntoArray(Words, TEXT(" "), false) >= 4)
				{
					Skeleton[bone].Offset[0] = FCString::Atof(*Words[1]);
					Skeleton[bone].Offset[1] = FCString::Atof(*Words[2]);
					Skeleton[bone].Offset[2] = FCString::Atof(*Words[3]);
					bToggle = false;
				}
			}
		}
		else if (Lines[i].StartsWith(TEXT("CHANNELS"), ESearchCase::IgnoreCase) == true)
		{
			TArray<FString> Words;
			if (Lines[i].ParseIntoArray(Words, TEXT(" "), false) >= 4)
			{
				Skeleton[bone].ChannelCount = FCString::Atoi(*Words[1]);
				if (Skeleton[bone].ChannelCount != 6)
				{
					if (GEngine)
					{
						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Channelcount must be 6 on bone:%u"), bone));
					}
					return false;
				}
				Skeleton[bone].XPos = Skeleton[bone].YPos = Skeleton[bone].ZPos = 0;
				Skeleton[bone].XRot = Skeleton[bone].YRot = Skeleton[bone].ZRot = 0;
				for (int32 j = 0; j < Skeleton[bone].ChannelCount; j++)
				{
					// Detect channel order
					// E.g.: Xposition Yposition Zposition Xrotation Yrotation Zrotation
					if (Words[j + 2].StartsWith(TEXT("Xposition"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].XPos = j;
					else if (Words[j + 2].StartsWith(TEXT("Yposition"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].YPos = j;
					else if (Words[j + 2].StartsWith(TEXT("Zposition"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].ZPos = j;
					else if (Words[j + 2].StartsWith(TEXT("Xrotation"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].XRot = j;
					else if (Words[j + 2].StartsWith(TEXT("Yrotation"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].YRot = j;
					else if (Words[j + 2].StartsWith(TEXT("Zrotation"), ESearchCase::IgnoreCase) == true)
						Skeleton[bone].ZRot = j;
				}
				// Check if we support rotation order
				if ((Skeleton[bone].XRot < Skeleton[bone].YRot) && (Skeleton[bone].YRot < Skeleton[bone].ZRot)) // e.g. 123
					Skeleton[bone].RotOrder = XYZ;
				else if ((Skeleton[bone].ZRot < Skeleton[bone].XRot) && (Skeleton[bone].XRot < Skeleton[bone].YRot)) // e.g. 312
					Skeleton[bone].RotOrder = ZXY;
				else if ((Skeleton[bone].YRot < Skeleton[bone].XRot) && (Skeleton[bone].XRot < Skeleton[bone].ZRot)) // e.g. 213
					Skeleton[bone].RotOrder = YXZ;
				else
				{
					if (GEngine)
					{
						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Rotation order not supported on bone:%u"), bone));
					}
					return false;
				}

				if (bone >= MAXBONES)
				{
					if (GEngine)
					{
						GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Too much bones in BVH file:%u"), bone));
					}
					return false;
				}
				bone++;
			}
		}
	} // end of for

	BoneNr = bone;

	return true;
}

// Connect to BVH server (for e.g. Axis Neuron SW)
bool AThirdPersonNeuronController::Connect(FString HostName, int32 Port)
{
	if (bConnected == true)
		return false;

	// Set up reference bone handling
	// Template does not support transition for the reference bone yet
	// Should be no problem, because normally reference bone does not change values.
	if (bReference == true)
	{
		// Skip reference bone x,y,z translation and x,y,z rotation
		// regardless if displacement is active or not (Axis Neuron sends always 6 floats)
		FloatSkip = 6;
	}

	// Create TCP Socket and connect
	ISocketSubsystem* const SocketSubSystem = ISocketSubsystem::Get();
	if (SocketSubSystem)
	{
		ReceiverSocket = SocketSubSystem->CreateSocket(NAME_Stream, TEXT("PerceptionNeuronSocket"), false);
		if (ReceiverSocket == NULL)
			return false;

		auto ResolveInfo = SocketSubSystem->GetHostByName(TCHAR_TO_ANSI(*HostName));
		while (!ResolveInfo->IsComplete());

		if (ResolveInfo->GetErrorCode() == 0)
		{
			const FInternetAddr* Addr = &ResolveInfo->GetResolvedAddress();
			uint32 IP;
			Addr->GetIp(IP);

			TSharedRef<FInternetAddr> InetAddr = SocketSubSystem->CreateInternetAddr();
			InetAddr->SetIp(IP);
			InetAddr->SetPort(Port);

			bConnected = ReceiverSocket->Connect(*InetAddr);
		}
	}

	return bConnected;
}

// Called when the game stops
void AThirdPersonNeuronController::BeginDestroy()
{
	Super::BeginDestroy();

	Disconnect();
}

// Disconnect from BVH server
void AThirdPersonNeuronController::Disconnect(void)
{
	if (bConnected == true)
	{
		bConnected = false;
		ReceiverSocket->Close();
	}
}

<|endoftext|>


<commit_before>/*
	Copyright (c) 2017-2018 Andrew Depke
*/
#include "LinuxStackTrace.h"

#include "../../Math/MathCore.h"

#include <cxxabi.h>
#include <execinfo.h>

namespace Red
{
	bool CaptureStackTrace(int MaxDepth, std::vector<StackFrame>* Output)
	{
		if (!Output || MaxDepth <= 0)
		{
			return false;
		}

		size_t Frames = 0;
		void* RawStackTrace[128];

		Frames = backtrace(RawStackTrace, Min(MaxDepth, 128));

		if (Frames <= 0)
		{
			return false;
		}

		char** StackTrace = backtrace_symbols(RawStackTrace, Frames);

		for (size_t Iter = 0; Iter < Frames; ++Iter)
		{
			std::string FrameString = StackTrace[Iter];

			StackFrame Frame;

			char FrameAddressBuffer[64];
			snprintf(FrameAddressBuffer, sizeof(FrameAddressBuffer), "0x%016llX", (unsigned long long int)RawStackTrace[Iter]);  // Assume 64 Bit Addresses.

			Frame.Address = FrameAddressBuffer;

			size_t ModuleNameEnd = FrameString.find('(') - 1;
			Frame.Module = FrameString.substr(0, ModuleNameEnd);

			size_t FunctionNameStart = FrameString.find('(') + 1;
			size_t FunctionNameEnd = FrameString.find('+') - 1;

#ifdef HAVE_CXA_DEMANGLE
			int OperationStatus = 0;

			char* DemangledName = abi::__cxa_demangle(FrameString.substr(FunctionNameStart, FunctionNameEnd - FunctionNameStart).c_str(), nullptr, nullptr, &OperationStatus);

			if (OperationStatus == 0)
			{
				Frame.Function = DemangledName;

				free(DemangledName);
			}

			else
			{
				Frame.Function = FrameString.substr(FunctionNameStart, FunctionNameEnd - FunctionNameStart);
			}
#else
			Frame.Function = FrameString.substr(FunctionNameStart, FunctionNameEnd - FunctionNameStart);
#endif
		}

		return true;
	}
}  // namespace Red
<commit_msg>Fixed Stack Tracer Not Outputting<commit_after>/*
	Copyright (c) 2017-2018 Andrew Depke
*/
#include "LinuxStackTrace.h"

#include "../../Math/MathCore.h"

#include <cxxabi.h>
#include <execinfo.h>

namespace Red
{
	bool CaptureStackTrace(int MaxDepth, std::vector<StackFrame>* Output)
	{
		if (!Output || MaxDepth <= 0)
		{
			return false;
		}

		size_t Frames = 0;
		void* RawStackTrace[128];

		Frames = backtrace(RawStackTrace, Min(MaxDepth, 128));

		if (Frames <= 0)
		{
			return false;
		}

		char** StackTrace = backtrace_symbols(RawStackTrace, Frames);

		for (size_t Iter = 0; Iter < Frames; ++Iter)
		{
			std::string FrameString = StackTrace[Iter];

			StackFrame Frame;

			char FrameAddressBuffer[64];
			snprintf(FrameAddressBuffer, sizeof(FrameAddressBuffer), "0x%016llX", (unsigned long long int)RawStackTrace[Iter]);  // Assume 64 Bit Addresses.

			Frame.Address = FrameAddressBuffer;

			size_t ModuleNameEnd = FrameString.find('(') - 1;
			Frame.Module = FrameString.substr(0, ModuleNameEnd);

			size_t FunctionNameStart = FrameString.find('(') + 1;
			size_t FunctionNameEnd = FrameString.find('+') - 1;

#ifdef HAVE_CXA_DEMANGLE
			int OperationStatus = 0;

			char* DemangledName = abi::__cxa_demangle(FrameString.substr(FunctionNameStart, FunctionNameEnd - FunctionNameStart).c_str(), nullptr, nullptr, &OperationStatus);

			if (OperationStatus == 0)
			{
				Frame.Function = DemangledName;

				free(DemangledName);
			}

			else
			{
				Frame.Function = FrameString.substr(FunctionNameStart, FunctionNameEnd - FunctionNameStart);
			}
#else
			Frame.Function = FrameString.substr(FunctionNameStart, FunctionNameEnd - FunctionNameStart);
#endif

			Output->push_back(Frame);
		}

		return true;
	}
}  // namespace Red
<|endoftext|>


<commit_before>/*
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   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., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "cameracontrollercomponent.h"

#include <core/debughelper.h>
#include <graphics/camera.h>
#include <engine/gameobject.h>
#include <graphics/engine.h>

REGISTER_OBJECTTYPE(GluonEngine, CameraControllerComponent)

using namespace GluonEngine;

class CameraControllerComponent::CameraControllerComponentPrivate
{
    public:
        CameraControllerComponentPrivate() { camera = 0; active = false; }

        GluonGraphics::Camera *camera;
        bool active;

        static GluonGraphics::Camera *activeCamera;
};

GluonGraphics::Camera* CameraControllerComponent::CameraControllerComponentPrivate::activeCamera = 0;

CameraControllerComponent::CameraControllerComponent ( QObject* parent ) : Component ( parent )
{
    d = new CameraControllerComponentPrivate;
}

CameraControllerComponent::CameraControllerComponent ( const CameraControllerComponent& other )
    : Component ( other ),
    d(other.d)
{
}

CameraControllerComponent::~CameraControllerComponent()
{
    delete d->camera;
    delete d;
}

void CameraControllerComponent::start()
{
    if(!d->camera)
        d->camera = new GluonGraphics::Camera();

    if(d->active)
        GluonGraphics::Engine::instance()->setActiveCamera(d->camera);
}

void CameraControllerComponent::draw ( int timeLapse )
{
    Q_UNUSED(timeLapse)

    #warning TODO: Set rotation/fov/all that crap
    d->camera->setPosition(gameObject()->position());
}

void CameraControllerComponent::update ( int elapsedMilliseconds )
{
    Q_UNUSED(elapsedMilliseconds)
}

bool CameraControllerComponent::isActive()
{
    return d->active;
}

void CameraControllerComponent::setActive(bool active)
{
    d->active = active;
    if(active && d->camera) {
        CameraControllerComponentPrivate::activeCamera = d->camera;
        GluonGraphics::Engine::instance()->setActiveCamera(d->camera);
    }
}

Q_EXPORT_PLUGIN2(gluon_component_cameracontroller, GluonEngine::CameraControllerComponent);

#include "cameracontrollercomponent.moc"
<commit_msg>Check whether we actually have a camera. Avoids crashes. :)<commit_after>/*
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   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., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "cameracontrollercomponent.h"

#include <core/debughelper.h>
#include <graphics/camera.h>
#include <engine/gameobject.h>
#include <graphics/engine.h>

REGISTER_OBJECTTYPE(GluonEngine, CameraControllerComponent)

using namespace GluonEngine;

class CameraControllerComponent::CameraControllerComponentPrivate
{
    public:
        CameraControllerComponentPrivate() { camera = 0; active = false; }

        GluonGraphics::Camera *camera;
        bool active;

        static GluonGraphics::Camera *activeCamera;
};

GluonGraphics::Camera* CameraControllerComponent::CameraControllerComponentPrivate::activeCamera = 0;

CameraControllerComponent::CameraControllerComponent ( QObject* parent ) : Component ( parent )
{
    d = new CameraControllerComponentPrivate;
}

CameraControllerComponent::CameraControllerComponent ( const CameraControllerComponent& other )
    : Component ( other ),
    d(other.d)
{
}

CameraControllerComponent::~CameraControllerComponent()
{
    delete d->camera;
    delete d;
}

void CameraControllerComponent::start()
{
    if(!d->camera)
        d->camera = new GluonGraphics::Camera();

    if(d->active)
        GluonGraphics::Engine::instance()->setActiveCamera(d->camera);
}

void CameraControllerComponent::draw ( int timeLapse )
{
    Q_UNUSED(timeLapse)

    #warning TODO: Set rotation/fov/all that crap
    if(d->camera)
        d->camera->setPosition(gameObject()->position());
}

void CameraControllerComponent::update ( int elapsedMilliseconds )
{
    Q_UNUSED(elapsedMilliseconds)
}

bool CameraControllerComponent::isActive()
{
    return d->active;
}

void CameraControllerComponent::setActive(bool active)
{
    d->active = active;
    if(active && d->camera) {
        CameraControllerComponentPrivate::activeCamera = d->camera;
        GluonGraphics::Engine::instance()->setActiveCamera(d->camera);
    }
}

Q_EXPORT_PLUGIN2(gluon_component_cameracontroller, GluonEngine::CameraControllerComponent);

#include "cameracontrollercomponent.moc"
<|endoftext|>