<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $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.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QtCore/QThread>
#include <QtCore/QSemaphore>
#include <QtCore/QElapsedTimer>
#include <QtNetwork/QTcpSocket>

#include "minihttpserver.h"
#include "../network-settings.h"

class tst_QTcpSocket_stresstest : public QObject
{
    Q_OBJECT
public:
    enum { AttemptCount = 100 };
    tst_QTcpSocket_stresstest();
    MiniHttpServer server;

public slots:
    void initTestCase_data();
    void init();

    void slotReadAll() { static_cast<QTcpSocket *>(sender())->readAll(); }

private Q_SLOTS:
    void blockingConnectDisconnect();
    void blockingPipelined();
    void blockingMultipleRequests();
    void connectDisconnect();
    void parallelConnectDisconnect_data();
    void parallelConnectDisconnect();
};

tst_QTcpSocket_stresstest::tst_QTcpSocket_stresstest()
{
}

void tst_QTcpSocket_stresstest::initTestCase_data()
{
    QTest::addColumn<bool>("isLocalhost");
    QTest::addColumn<QString>("hostname");
    QTest::addColumn<int>("port");

    QTest::newRow("localhost") << false << "localhost" << server.port();
    QTest::newRow("remote") << true << QtNetworkSettings::serverName() << 80;
}

void tst_QTcpSocket_stresstest::init()
{
    if (qgetenv("QTCPSOCKET_STRESSTEST").toInt() == 0)
        QSKIP("Stress test disabled", SkipAll);
}

void tst_QTcpSocket_stresstest::blockingConnectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount; ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                     "Connection: close\r\n"
                     "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                     "Host: " + hostname.toLatin1() + "\r\n"
                     "\r\n");
        while (socket.bytesToWrite())
            QVERIFY2(socket.waitForBytesWritten(), "Timeout");

        QElapsedTimer timeout;
        timeout.start();
        while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
            socket.waitForReadyRead();
            socket.readAll(); // discard
        }
    }
}

void tst_QTcpSocket_stresstest::blockingPipelined()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount / 2; ++i) {
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        for (int j = 0 ; j < 3; ++j) {
            qDebug("Attempt %d%c", i, 'a' + j);
            socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                         "Connection: " + QByteArray(j == 2 ? "close" : "keep-alive") + "\r\n"
                         "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                         "Host: " + hostname.toLatin1() + "\r\n"
                         "\r\n");
            while (socket.bytesToWrite())
                QVERIFY2(socket.waitForBytesWritten(), "Timeout");
        }

        QElapsedTimer timeout;
        timeout.start();
        while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
            socket.waitForReadyRead();
            socket.readAll(); // discard
        }
    }
}

void tst_QTcpSocket_stresstest::blockingMultipleRequests()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount / 5; ++i) {
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        for (int j = 0 ; j < 5; ++j) {
            qDebug("Attempt %d", i * 5 + j);

            socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                         "Connection: keep-alive\r\n"
                         "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                         "Host: " + hostname.toLatin1() + "\r\n"
                         "\r\n");
            while (socket.bytesToWrite())
                QVERIFY2(socket.waitForBytesWritten(), "Timeout");

            QElapsedTimer timeout;
            timeout.start();

            qint64 bytesRead = 0;
            qint64 bytesExpected = -1;
            QByteArray buffer;
            while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
                socket.waitForReadyRead();
                buffer += socket.readAll();
                int pos = buffer.indexOf("\r\n\r\n");
                if (pos == -1)
                    continue;

                bytesRead = buffer.length() - pos - 1;

                buffer.truncate(pos);
                buffer = buffer.toLower();
                pos = buffer.indexOf("\r\ncontent-length: ");
                if (pos == -1)
                    break;
                pos += strlen("\r\ncontent-length: ");

                int eol = buffer.indexOf("\r\n", pos + 2);
                if (eol == -1)
                    break;

                bytesExpected = buffer.mid(pos, eol - pos).toLongLong();
                break;
            }
            QVERIFY2(!timeout.hasExpired(10000), "Timeout");

            while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000) && bytesExpected > bytesRead) {
                socket.waitForReadyRead();
                bytesRead += socket.read(bytesExpected - bytesRead).length(); // discard
            }
            QVERIFY2(!timeout.hasExpired(10000), "Timeout");
        }

        socket.disconnectFromHost();
        QVERIFY(socket.state() == QAbstractSocket::UnconnectedState);
    }
}

void tst_QTcpSocket_stresstest::connectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount; ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket socket;
        socket.connectToHost(hostname, port);

        socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                     "Connection: close\r\n"
                     "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                     "Host: " + hostname.toLatin1() + "\r\n"
                     "\r\n");
        connect(&socket, SIGNAL(readyRead()), SLOT(slotReadAll()));

        QTestEventLoop::instance().connect(&socket, SIGNAL(disconnected()), SLOT(exitLoop()));
        QTestEventLoop::instance().enterLoop(30);
        QVERIFY2(!QTestEventLoop::instance().timeout(), "Timeout");
    }
}

void tst_QTcpSocket_stresstest::parallelConnectDisconnect_data()
{
    QTest::addColumn<int>("parallelAttempts");
    QTest::newRow("1") << 1;
    QTest::newRow("2") << 2;
    QTest::newRow("4") << 4;
    QTest::newRow("5") << 5;
    QTest::newRow("10") << 10;
    QTest::newRow("25") << 25;
    QTest::newRow("100") << 100;
}

void tst_QTcpSocket_stresstest::parallelConnectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);
    QFETCH(int, parallelAttempts);

    for (int i = 0; i < AttemptCount/qMax(2, parallelAttempts/4); ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket *socket = new QTcpSocket[parallelAttempts];
        for (int j = 0; j < parallelAttempts; ++j) {
            socket[j].connectToHost(hostname, port);

            socket[j].write("GET /qtest/bigfile HTTP/1.1\r\n"
                            "Connection: close\r\n"
                            "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                            "Host: " + hostname.toLatin1() + "\r\n"
                            "\r\n");
            connect(&socket[j], SIGNAL(readyRead()), SLOT(slotReadAll()));

            QTestEventLoop::instance().connect(&socket[j], SIGNAL(disconnected()), SLOT(exitLoop()));
        }

        QElapsedTimer timeout;
        timeout.start();
        while (!timeout.hasExpired(30000)) {
            QTestEventLoop::instance().enterLoop(10);
            int done = 0;
            for (int j = 0; j < parallelAttempts; ++j)
                done += socket[j].state() == QAbstractSocket::UnconnectedState ? 1 : 0;
            if (done == parallelAttempts)
                break;
        }
        delete[] socket;
        QVERIFY2(!timeout.hasExpired(30000), "Timeout");
        //qDebug() << "Run-time was" << timeout.elapsed();
    }
}

QTEST_MAIN(tst_QTcpSocket_stresstest);

#include "tst_qtcpsocket_stresstest.moc"
<commit_msg>Add some statistics in the transfer rate<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $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.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QtCore/QThread>
#include <QtCore/QSemaphore>
#include <QtCore/QElapsedTimer>
#include <QtNetwork/QTcpSocket>

#include "minihttpserver.h"
#include "../network-settings.h"

class tst_QTcpSocket_stresstest : public QObject
{
    Q_OBJECT
public:
    enum { AttemptCount = 100 };
    tst_QTcpSocket_stresstest();
    MiniHttpServer server;

    qint64 byteCounter;

public slots:
    void initTestCase_data();
    void init();

    void slotReadAll() { byteCounter += static_cast<QTcpSocket *>(sender())->readAll().size(); }

private Q_SLOTS:
    void blockingConnectDisconnect();
    void blockingPipelined();
    void blockingMultipleRequests();
    void connectDisconnect();
    void parallelConnectDisconnect_data();
    void parallelConnectDisconnect();
};

tst_QTcpSocket_stresstest::tst_QTcpSocket_stresstest()
{
}

void tst_QTcpSocket_stresstest::initTestCase_data()
{
    QTest::addColumn<bool>("isLocalhost");
    QTest::addColumn<QString>("hostname");
    QTest::addColumn<int>("port");

    QTest::newRow("localhost") << true << "localhost" << server.port();
    QTest::newRow("remote") << false << QtNetworkSettings::serverName() << 80;
}

void tst_QTcpSocket_stresstest::init()
{
    if (qgetenv("QTCPSOCKET_STRESSTEST").toInt() == 0)
        QSKIP("Stress test disabled", SkipAll);
}

void tst_QTcpSocket_stresstest::blockingConnectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    double avg = 0;
    for (int i = 0; i < AttemptCount; ++i) {
        QElapsedTimer timeout;
        byteCounter = 0;
        timeout.start();

        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        socket.write("GET /qtest/mediumfile HTTP/1.1\r\n"
                     "Connection: close\r\n"
                     "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                     "Host: " + hostname.toLatin1() + "\r\n"
                     "\r\n");
        while (socket.bytesToWrite())
            QVERIFY2(socket.waitForBytesWritten(), "Timeout");

        while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
            socket.waitForReadyRead();
            byteCounter += socket.readAll().size(); // discard
        }
        double rate = (byteCounter / timeout.elapsed());
        avg = (i * avg + rate) / (i + 1);
        qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
                << (rate / 1024.0 / 1024 * 1000) << "MB/s";
    }
    qDebug() << "Average transfer rate was" << (avg / 1024.0 / 1024 * 1000) << "MB/s";
}

void tst_QTcpSocket_stresstest::blockingPipelined()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    double avg = 0;
    for (int i = 0; i < AttemptCount / 2; ++i) {
        QElapsedTimer timeout;
        byteCounter = 0;
        timeout.start();

        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        for (int j = 0 ; j < 3; ++j) {
            qDebug("Attempt %d%c", i, 'a' + j);
            socket.write("GET /qtest/mediumfile HTTP/1.1\r\n"
                         "Connection: " + QByteArray(j == 2 ? "close" : "keep-alive") + "\r\n"
                         "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                         "Host: " + hostname.toLatin1() + "\r\n"
                         "\r\n");
            while (socket.bytesToWrite())
                QVERIFY2(socket.waitForBytesWritten(), "Timeout");
        }

        while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
            socket.waitForReadyRead();
            byteCounter += socket.readAll().size(); // discard
        }

        double rate = (byteCounter / timeout.elapsed());
        avg = (i * avg + rate) / (i + 1);
        qDebug() << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
                << (rate / 1024.0 / 1024 * 1000) << "MB/s";
    }
    qDebug() << "Average transfer rate was" << (avg / 1024.0 / 1024 * 1000) << "MB/s";
}

void tst_QTcpSocket_stresstest::blockingMultipleRequests()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    double avg = 0;
    for (int i = 0; i < AttemptCount / 5; ++i) {
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        for (int j = 0 ; j < 5; ++j) {
            QElapsedTimer timeout;
            byteCounter = 0;
            timeout.start();

            socket.write("GET /qtest/mediumfile HTTP/1.1\r\n"
                         "Connection: keep-alive\r\n"
                         "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                         "Host: " + hostname.toLatin1() + "\r\n"
                         "\r\n");
            while (socket.bytesToWrite())
                QVERIFY2(socket.waitForBytesWritten(), "Timeout");

            qint64 bytesRead = 0;
            qint64 bytesExpected = -1;
            QByteArray buffer;
            while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
                socket.waitForReadyRead();
                buffer += socket.readAll();
                byteCounter += buffer.size();
                int pos = buffer.indexOf("\r\n\r\n");
                if (pos == -1)
                    continue;

                bytesRead = buffer.length() - pos - 4;

                buffer.truncate(pos + 2);
                buffer = buffer.toLower();
                pos = buffer.indexOf("\r\ncontent-length: ");
                if (pos == -1) {
                    qWarning() << "no content-length:" << QString(buffer);
                    break;
                }
                pos += strlen("\r\ncontent-length: ");

                int eol = buffer.indexOf("\r\n", pos + 2);
                if (eol == -1) {
                    qWarning() << "invalid header";
                    break;
                }

                bytesExpected = buffer.mid(pos, eol - pos).toLongLong();
                break;
            }
            QVERIFY(bytesExpected > 0);
            QVERIFY2(!timeout.hasExpired(10000), "Timeout");

            while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000) && bytesExpected > bytesRead) {
                socket.waitForReadyRead();
                int blocklen = socket.read(bytesExpected - bytesRead).length(); // discard
                bytesRead += blocklen;
                byteCounter += blocklen;
            }
            QVERIFY2(!timeout.hasExpired(10000), "Timeout");
            QCOMPARE(bytesRead, bytesExpected);

            double rate = (byteCounter / timeout.elapsed());
            avg = (i * avg + rate) / (i + 1);
            qDebug() << i * 5 + j << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
                    << (rate / 1024.0 / 1024 * 1000) << "MB/s";
        }

        socket.disconnectFromHost();
        QVERIFY(socket.state() == QAbstractSocket::UnconnectedState);
    }
    qDebug() << "Average transfer rate was" << (avg / 1024.0 / 1024 * 1000) << "MB/s";
}

void tst_QTcpSocket_stresstest::connectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    double avg = 0;
    for (int i = 0; i < AttemptCount; ++i) {
        QElapsedTimer timeout;
        byteCounter = 0;
        timeout.start();

        QTcpSocket socket;
        socket.connectToHost(hostname, port);

        socket.write("GET /qtest/mediumfile HTTP/1.1\r\n"
                     "Connection: close\r\n"
                     "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                     "Host: " + hostname.toLatin1() + "\r\n"
                     "\r\n");
        connect(&socket, SIGNAL(readyRead()), SLOT(slotReadAll()));

        QTestEventLoop::instance().connect(&socket, SIGNAL(disconnected()), SLOT(exitLoop()));
        QTestEventLoop::instance().enterLoop(30);
        QVERIFY2(!QTestEventLoop::instance().timeout(), "Timeout");
        double rate = (byteCounter / timeout.elapsed());
        avg = (i * avg + rate) / (i + 1);
        qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
                << (rate / 1024.0 / 1024 * 1000) << "MB/s";
    }
    qDebug() << "Average transfer rate was" << (avg / 1024.0 / 1024 * 1000) << "MB/s";
}

void tst_QTcpSocket_stresstest::parallelConnectDisconnect_data()
{
    QTest::addColumn<int>("parallelAttempts");
    QTest::newRow("1") << 1;
    QTest::newRow("2") << 2;
    QTest::newRow("4") << 4;
    QTest::newRow("5") << 5;
    QTest::newRow("6") << 6;
    QTest::newRow("8") << 8;
    QTest::newRow("10") << 10;
    QTest::newRow("25") << 25;
    QTest::newRow("100") << 100;
    QTest::newRow("500") << 500;
}

void tst_QTcpSocket_stresstest::parallelConnectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);
    QFETCH(int, parallelAttempts);

    if (parallelAttempts > 100) {
        QFETCH_GLOBAL(bool, isLocalhost);
        if (!isLocalhost)
            QSKIP("Localhost-only test", SkipSingle);
    }

    double avg = 0;
    for (int i = 0; i < qMax(2, AttemptCount/qMax(2, parallelAttempts/4)); ++i) {
        QElapsedTimer timeout;
        byteCounter = 0;
        timeout.start();

        QTcpSocket *socket = new QTcpSocket[parallelAttempts];
        for (int j = 0; j < parallelAttempts; ++j) {
            socket[j].connectToHost(hostname, port);

            socket[j].write("GET /qtest/mediumfile HTTP/1.1\r\n"
                            "Connection: close\r\n"
                            "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                            "Host: " + hostname.toLatin1() + "\r\n"
                            "\r\n");
            connect(&socket[j], SIGNAL(readyRead()), SLOT(slotReadAll()));

            QTestEventLoop::instance().connect(&socket[j], SIGNAL(disconnected()), SLOT(exitLoop()));
        }

        while (!timeout.hasExpired(30000)) {
            QTestEventLoop::instance().enterLoop(10);
            int done = 0;
            for (int j = 0; j < parallelAttempts; ++j)
                done += socket[j].state() == QAbstractSocket::UnconnectedState ? 1 : 0;
            if (done == parallelAttempts)
                break;
        }
        delete[] socket;
        QVERIFY2(!timeout.hasExpired(30000), "Timeout");
        double rate = (byteCounter / timeout.elapsed());
        avg = (i * avg + rate) / (i + 1);
        qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
                << (rate / 1024.0 / 1024 * 1000) << "MB/s";
    }
    qDebug() << "Average transfer rate was" << (avg / 1024.0 / 1024 * 1000) << "MB/s";
}

QTEST_MAIN(tst_QTcpSocket_stresstest);

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


<commit_before>/** @file
    @brief Implementation for class that tracks and identifies LEDs.

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Internal Includes
#include "BeaconBasedPoseEstimator.h"

// Library/third-party includes
#include <osvr/Util/QuatlibInteropC.h>

// Standard includes
// - none

namespace osvr {
namespace vbtracker {

    // clang-format off
    // Default 3D locations for the beacons on an OSVR HDK face plate, in
    // millimeters
    const DoubleVecVec OsvrHdkLedLocations_SENSOR0 = {
        {-85, 3, 24.09},
        { -83.2, -14.01, 13.89 },
        { -47, 51, 24.09 },
        { 47, 51, 24.09 },
        { 86.6, 2.65, 24.09 },
        { 85.5, -14.31, 13.89 },
        { 85.2, 19.68, 13.89 },
        { 21, 51, 13.09 },
        { -21, 51, 13.09 },
        { -84.2, 19.99, 13.89 },
        { -60.41, 47.55, 44.6 },
        { -80.42, 20.48, 42.9 },
        { -82.01, 2.74, 42.4 },
        { -80.42, -14.99, 42.9 },
        { -60.41, -10.25, 48.1 },
        { -60.41, 15.75, 48.1 },
        { -30.41, 32.75, 50.5 },
        { -31.41, 47.34, 47 },
        { -0.41, -15.25, 51.3 },
        { -30.41, -27.25, 50.5 },
        { -60.44, -41.65, 45.1 },
        { -22.41, -41.65, 47.8 },
        { 21.59, -41.65, 47.8 },
        { 59.59, -41.65, 45.1 },
        { 79.63, -14.98, 42.9 },
        { 29.59, -27.25, 50.5 },
        { 81.19, 2.74, 42.4 },
        { 79.61, 20.48, 42.9 },
        { 59.59, 47.55, 44.6 },
        { 30.59, 47.55, 47 },
        { 29.59, 32.75, 50.5 },
        { -0.41, 20.75, 51.3 },
        { 59.59, 15.75, 48.1 },
        { 59.59, -10.25, 48.1 }
    };

    // Default 3D locations for the beacons on an OSVR HDK back plate, in
    // millimeters
    const DoubleVecVec OsvrHdkLedLocations_SENSOR1 = {
        {1, 23.8, 0},
        { 11, 5.8, 0 },
        { 9, -23.8, 0 },
        { 0, -8.8, 0 },
        { -9, -23.8, 0 },
        { -12, 5.8, 0 }
    };
    // clang-format on

    BeaconBasedPoseEstimator::BeaconBasedPoseEstimator(
        const DoubleVecVec &cameraMatrix, const std::vector<double> &distCoeffs,
        const DoubleVecVec &beacons) {
        SetBeacons(beacons);
        SetCameraMatrix(cameraMatrix);
        SetDistCoeffs(distCoeffs);
        m_gotPose = false;
    }

    bool BeaconBasedPoseEstimator::SetBeacons(const DoubleVecVec &beacons) {
        // Our existing pose won't match anymore.
        m_gotPose = false;

        for (int i = 0; i < beacons.size(); i++) {
            if (beacons[i].size() != 3) {
                m_beacons.clear();
                return false;
            }
            cv::Point3f p(static_cast<float>(beacons[i][0]),
                          static_cast<float>(beacons[i][1]),
                          static_cast<float>(beacons[i][2]));
            m_beacons.push_back(p);
        }

        return true;
    }

    bool BeaconBasedPoseEstimator::SetCameraMatrix(
        const DoubleVecVec &cameraMatrix) {
        // Our existing pose won't match anymore.
        m_gotPose = false;

        // Construct the camera matrix from the vectors we received.
        if (cameraMatrix.size() != 3) {
            return false;
        }
        for (size_t i = 0; i < cameraMatrix.size(); i++) {
            if (cameraMatrix[i].size() != 3) {
                return false;
            }
        }
        cv::Mat newCameraMatrix(static_cast<int>(cameraMatrix.size()),
                                static_cast<int>(cameraMatrix[0].size()),
                                CV_64F);
        for (int i = 0; i < cameraMatrix.size(); i++) {
            for (int j = 0; j < cameraMatrix[i].size(); j++) {
                newCameraMatrix.at<double>(i, j) = cameraMatrix[i][j];
            }
        }

        m_cameraMatrix = newCameraMatrix;
        //    std::cout << "XXX cameraMatrix =" << std::endl << m_cameraMatrix
        //    << std::endl;
        return true;
    }

    bool BeaconBasedPoseEstimator::SetDistCoeffs(
        const std::vector<double> &distCoeffs) {
        // Our existing pose won't match anymore.
        m_gotPose = false;

        // Construct the distortion matrix from the vectors we received.
        if (distCoeffs.size() < 5) {
            return false;
        }
        cv::Mat newDistCoeffs(static_cast<int>(distCoeffs.size()), 1, CV_64F);
        for (int i = 0; i < distCoeffs.size(); i++) {
            newDistCoeffs.at<double>(i, 0) = distCoeffs[i];
        }

        m_distCoeffs = newDistCoeffs;
        //    std::cout << "XXX distCoeffs =" << std::endl << m_distCoeffs <<
        //    std::endl;
        return true;
    }

    static const int OUTLIERS_PERMITTED = 2;
    /// We want at least five corresponding points (this is somewhat arbitrary,
    /// but must be at least 5 to allow for 2 outliers below).
    static const int MIN_OBJECT_POINTS = OUTLIERS_PERMITTED + 3;

    bool
    BeaconBasedPoseEstimator::EstimatePoseFromLeds(const LedGroup &leds,
                                                   OSVR_PoseState &outPose) {
        auto ret = m_estimatePoseFromLeds(leds, outPose);
        m_gotPose = ret;
        return ret;
    }

    bool
    BeaconBasedPoseEstimator::m_estimatePoseFromLeds(const LedGroup &leds,
                                                     OSVR_PoseState &outPose) {
        // We need to get a pair of matched vectors of points: 2D locations
        // with in the image and 3D locations in model space.  There needs to
        // be a correspondence between the points in these vectors, such that
        // the ith element in one matches the ith element in the other.  We
        // make these by looking up the locations of LEDs with known identifiers
        // and pushing both onto the vectors at the same time.

        std::vector<cv::Point3f> objectPoints;
        std::vector<cv::Point2f> imagePoints;
        auto const beaconsSize = m_beacons.size();
        for (auto const &led : leds) {
            if (!led.identified()) {
                continue;
            }
            auto id = led.getID();
            if (id < beaconsSize) {
                imagePoints.push_back(led.getLocation());
                objectPoints.push_back(m_beacons[id]);
            }
        }

        // Make sure we have enough points to do our estimation.
        if (objectPoints.size() < MIN_OBJECT_POINTS) {
            return false;
        }

        // Produce an estimate of the translation and rotation needed to take
        // points from model space into camera space.  We allow for at most
        // OUTLIERS_PERMITTED outliers. Even in simulation data, we sometimes
        // find duplicate IDs for LEDs, indicating that we are getting
        // mis-identified ones sometimes.
        cv::solvePnPRansac(
            objectPoints, imagePoints, m_cameraMatrix, m_distCoeffs, m_rvec,
            m_tvec, false, 100, 8.0f,
            static_cast<int>(objectPoints.size() - OUTLIERS_PERMITTED));

        //    std::cout << "XXX tvec = " << m_tvec << std::endl;
        //    std::cout << "XXX rvec = " << m_rvec << std::endl;

        //==========================================================================
        // Convert this into an OSVR representation of the transformation that
        // gives the pose of the HDK origin in the camera coordinate system,
        // switching units to meters and encoding the angle in a unit
        // quaternion.
        // The matrix described by rvec and tvec takes points in model space
        // (the space where the LEDs are defined, which is in mm away from an
        // implied origin) into a coordinate system where the center is at the
        // camera's origin, with X to the right, Y down, and Z in the direction
        // that the camera is facing (but still in the original units of mm):
        //  |Xc|   |r11 r12 r13 t1| |Xm|
        //  |Yc| = |r21 r22 r23 t2|*|Ym|
        //  |Zc|   |r31 r32 r33 t3| |Zm|
        //                          |1 |
        //  That is, it rotates into the camera coordinate system and then adds
        // the translation, which is in the camera coordinate system.
        //  This is the transformation we want, since it reports the sensor's
        // position and orientation in camera space, except that we want to convert
        // the units into meters and the orientation into a Quaternion.
        //  NOTE: This is a right-handed coordinate system with X pointing
        // towards the right from the camera center of projection, Y pointing
        // down, and Z pointing along the camera viewing direction.

        // Compose the transform in original units.
        // We start by making a 3x3 rotation matrix out of the rvec, which
        // is done by a function that for some reason is named Rodrigues.
        cv::Mat rot;
        cv::Rodrigues(m_rvec, rot);

        // TODO: Replace this code with Eigen code.

        if (rot.type() != CV_64F) {
            return false;
        }

        // Get the forward transform
        q_xyz_quat_type forward;
        forward.xyz[Q_X] = m_tvec.at<double>(0);
        forward.xyz[Q_Y] = m_tvec.at<double>(1);
        forward.xyz[Q_Z] = m_tvec.at<double>(2);

        // Fill in a 4x4 matrix that starts as the identity
        // matrix with the 3x3 part from the rotation matrix.
        q_matrix_type rot4x4;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if ((i < 3) && (j < 3)) {
                    rot4x4[i][j] = rot.at<double>(i, j);
                } else {
                    if (i == j) {
                        rot4x4[i][j] = 1;
                    } else {
                        rot4x4[i][j] = 0;
                    }
                }
            }
        }
        q_from_row_matrix(forward.quat, rot4x4);

        // Scale to meters
        q_vec_scale(forward.xyz, 1e-3, forward.xyz);

        //==============================================================
        // Put into OSVR format.
        osvrPose3FromQuatlib(&outPose, &forward);
        return true;
    }

    bool BeaconBasedPoseEstimator::ProjectBeaconsToImage(
        std::vector<cv::Point2f> &out) {
        // Make sure we have a pose.  Otherwise, we can't do anything.
        if (!m_gotPose) {
            return false;
        }

        cv::projectPoints(m_beacons, m_rvec, m_tvec, m_cameraMatrix,
                          m_distCoeffs, out);
        return true;
    }

} // End namespace vbtracker
} // End namespace osvr
<commit_msg>Moved position of two LEDs in line with others, to match observations.  Adjusted the number of points needed for tracking, increasing it to 4, to increase stability.  Reduced the maximum number of iterations on the PNP solver from 100 to 5 to maintain 100Hz performance even for estimation of bad poses.  Re-using previous pose estimate in PNP tracker, which produces much more stable position estimates without apparently slowing down original tracking estimation.<commit_after>/** @file
    @brief Implementation for class that tracks and identifies LEDs.

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Internal Includes
#include "BeaconBasedPoseEstimator.h"

// Library/third-party includes
#include <osvr/Util/QuatlibInteropC.h>

// Standard includes
// - none

namespace osvr {
namespace vbtracker {

    // clang-format off
    // Default 3D locations for the beacons on an OSVR HDK face plate, in
    // millimeters
    const DoubleVecVec OsvrHdkLedLocations_SENSOR0 = {
        {-85, 3, 24.09},
        { -83.2, -14.01, 13.89 },
        { -47, 51, 24.09 },
        { 47, 51, 24.09 },
        { 86.6, 2.65, 24.09 },
        { 85.5, -14.31, 13.89 },
        { 85.2, 19.68, 13.89 },
        { 21, 51, 24.09 },  // Original spec was 13.09, new position works better
        { -21, 51, 24.09 }, // Original spec was 13.09, new position works better
        { -84.2, 19.99, 13.89 },
        { -60.41, 47.55, 44.6 },
        { -80.42, 20.48, 42.9 },
        { -82.01, 2.74, 42.4 },
        { -80.42, -14.99, 42.9 },
        { -60.41, -10.25, 48.1 },
        { -60.41, 15.75, 48.1 },
        { -30.41, 32.75, 50.5 },
        { -31.41, 47.34, 47 },
        { -0.41, -15.25, 51.3 },
        { -30.41, -27.25, 50.5 },
        { -60.44, -41.65, 45.1 },
        { -22.41, -41.65, 47.8 },
        { 21.59, -41.65, 47.8 },
        { 59.59, -41.65, 45.1 },
        { 79.63, -14.98, 42.9 },
        { 29.59, -27.25, 50.5 },
        { 81.19, 2.74, 42.4 },
        { 79.61, 20.48, 42.9 },
        { 59.59, 47.55, 44.6 },
        { 30.59, 47.55, 47 },
        { 29.59, 32.75, 50.5 },
        { -0.41, 20.75, 51.3 },
        { 59.59, 15.75, 48.1 },
        { 59.59, -10.25, 48.1 }
    };

    // Default 3D locations for the beacons on an OSVR HDK back plate, in
    // millimeters
    const DoubleVecVec OsvrHdkLedLocations_SENSOR1 = {
        {1, 23.8, 0},
        { 11, 5.8, 0 },
        { 9, -23.8, 0 },
        { 0, -8.8, 0 },
        { -9, -23.8, 0 },
        { -12, 5.8, 0 }
    };
    // clang-format on

    BeaconBasedPoseEstimator::BeaconBasedPoseEstimator(
        const DoubleVecVec &cameraMatrix, const std::vector<double> &distCoeffs,
        const DoubleVecVec &beacons) {
        SetBeacons(beacons);
        SetCameraMatrix(cameraMatrix);
        SetDistCoeffs(distCoeffs);
        m_gotPose = false;
    }

    bool BeaconBasedPoseEstimator::SetBeacons(const DoubleVecVec &beacons) {
        // Our existing pose won't match anymore.
        m_gotPose = false;

        for (int i = 0; i < beacons.size(); i++) {
            if (beacons[i].size() != 3) {
                m_beacons.clear();
                return false;
            }
            cv::Point3f p(static_cast<float>(beacons[i][0]),
                          static_cast<float>(beacons[i][1]),
                          static_cast<float>(beacons[i][2]));
            m_beacons.push_back(p);
        }

        return true;
    }

    bool BeaconBasedPoseEstimator::SetCameraMatrix(
        const DoubleVecVec &cameraMatrix) {
        // Our existing pose won't match anymore.
        m_gotPose = false;

        // Construct the camera matrix from the vectors we received.
        if (cameraMatrix.size() != 3) {
            return false;
        }
        for (size_t i = 0; i < cameraMatrix.size(); i++) {
            if (cameraMatrix[i].size() != 3) {
                return false;
            }
        }
        cv::Mat newCameraMatrix(static_cast<int>(cameraMatrix.size()),
                                static_cast<int>(cameraMatrix[0].size()),
                                CV_64F);
        for (int i = 0; i < cameraMatrix.size(); i++) {
            for (int j = 0; j < cameraMatrix[i].size(); j++) {
                newCameraMatrix.at<double>(i, j) = cameraMatrix[i][j];
            }
        }

        m_cameraMatrix = newCameraMatrix;
        //    std::cout << "XXX cameraMatrix =" << std::endl << m_cameraMatrix
        //    << std::endl;
        return true;
    }

    bool BeaconBasedPoseEstimator::SetDistCoeffs(
        const std::vector<double> &distCoeffs) {
        // Our existing pose won't match anymore.
        m_gotPose = false;

        // Construct the distortion matrix from the vectors we received.
        if (distCoeffs.size() < 5) {
            return false;
        }
        cv::Mat newDistCoeffs(static_cast<int>(distCoeffs.size()), 1, CV_64F);
        for (int i = 0; i < distCoeffs.size(); i++) {
            newDistCoeffs.at<double>(i, 0) = distCoeffs[i];
        }

        m_distCoeffs = newDistCoeffs;
        //    std::cout << "XXX distCoeffs =" << std::endl << m_distCoeffs <<
        //    std::endl;
        return true;
    }

    static const int OUTLIERS_PERMITTED = 2;
    /// We want at least five corresponding points (this is somewhat arbitrary,
    /// but must be at least 5 to allow for 2 outliers below).
    static const int MIN_OBJECT_POINTS = OUTLIERS_PERMITTED + 4;

    bool
    BeaconBasedPoseEstimator::EstimatePoseFromLeds(const LedGroup &leds,
                                                   OSVR_PoseState &outPose) {
        auto ret = m_estimatePoseFromLeds(leds, outPose);
        m_gotPose = ret;
        return ret;
    }

    bool
    BeaconBasedPoseEstimator::m_estimatePoseFromLeds(const LedGroup &leds,
                                                     OSVR_PoseState &outPose) {
        // We need to get a pair of matched vectors of points: 2D locations
        // with in the image and 3D locations in model space.  There needs to
        // be a correspondence between the points in these vectors, such that
        // the ith element in one matches the ith element in the other.  We
        // make these by looking up the locations of LEDs with known identifiers
        // and pushing both onto the vectors at the same time.

        std::vector<cv::Point3f> objectPoints;
        std::vector<cv::Point2f> imagePoints;
        auto const beaconsSize = m_beacons.size();
        for (auto const &led : leds) {
            if (!led.identified()) {
                continue;
            }
            auto id = led.getID();
            if (id < beaconsSize) {
                imagePoints.push_back(led.getLocation());
                objectPoints.push_back(m_beacons[id]);
            }
        }

        // Make sure we have enough points to do our estimation.
        if (objectPoints.size() < MIN_OBJECT_POINTS) {
            return false;
        }

        // Produce an estimate of the translation and rotation needed to take
        // points from model space into camera space.  We allow for at most
        // OUTLIERS_PERMITTED outliers. Even in simulation data, we sometimes
        // find duplicate IDs for LEDs, indicating that we are getting
        // mis-identified ones sometimes.
        cv::solvePnPRansac(
            objectPoints, imagePoints, m_cameraMatrix, m_distCoeffs, m_rvec,
            m_tvec, true, 5, 8.0f,
            static_cast<int>(objectPoints.size() - OUTLIERS_PERMITTED));

        //==========================================================================
        // Convert this into an OSVR representation of the transformation that
        // gives the pose of the HDK origin in the camera coordinate system,
        // switching units to meters and encoding the angle in a unit
        // quaternion.
        // The matrix described by rvec and tvec takes points in model space
        // (the space where the LEDs are defined, which is in mm away from an
        // implied origin) into a coordinate system where the center is at the
        // camera's origin, with X to the right, Y down, and Z in the direction
        // that the camera is facing (but still in the original units of mm):
        //  |Xc|   |r11 r12 r13 t1| |Xm|
        //  |Yc| = |r21 r22 r23 t2|*|Ym|
        //  |Zc|   |r31 r32 r33 t3| |Zm|
        //                          |1 |
        //  That is, it rotates into the camera coordinate system and then adds
        // the translation, which is in the camera coordinate system.
        //  This is the transformation we want, since it reports the sensor's
        // position and orientation in camera space, except that we want to convert
        // the units into meters and the orientation into a Quaternion.
        //  NOTE: This is a right-handed coordinate system with X pointing
        // towards the right from the camera center of projection, Y pointing
        // down, and Z pointing along the camera viewing direction.

        // Compose the transform in original units.
        // We start by making a 3x3 rotation matrix out of the rvec, which
        // is done by a function that for some reason is named Rodrigues.
        cv::Mat rot;
        cv::Rodrigues(m_rvec, rot);

        // TODO: Replace this code with Eigen code.

        if (rot.type() != CV_64F) {
            return false;
        }

        // Get the forward transform
        q_xyz_quat_type forward;
        forward.xyz[Q_X] = m_tvec.at<double>(0);
        forward.xyz[Q_Y] = m_tvec.at<double>(1);
        forward.xyz[Q_Z] = m_tvec.at<double>(2);

        // Fill in a 4x4 matrix that starts as the identity
        // matrix with the 3x3 part from the rotation matrix.
        q_matrix_type rot4x4;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if ((i < 3) && (j < 3)) {
                    rot4x4[i][j] = rot.at<double>(i, j);
                } else {
                    if (i == j) {
                        rot4x4[i][j] = 1;
                    } else {
                        rot4x4[i][j] = 0;
                    }
                }
            }
        }
        q_from_row_matrix(forward.quat, rot4x4);

        // Scale to meters
        q_vec_scale(forward.xyz, 1e-3, forward.xyz);

        //==============================================================
        // Put into OSVR format.
        osvrPose3FromQuatlib(&outPose, &forward);
        return true;
    }

    bool BeaconBasedPoseEstimator::ProjectBeaconsToImage(
        std::vector<cv::Point2f> &out) {
        // Make sure we have a pose.  Otherwise, we can't do anything.
        if (!m_gotPose) {
            return false;
        }

        cv::projectPoints(m_beacons, m_rvec, m_tvec, m_cameraMatrix,
                          m_distCoeffs, out);
        return true;
    }

} // End namespace vbtracker
} // End namespace osvr
<|endoftext|>


<commit_before>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2011  Sandro Santilli <strk@keybit.net>
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: perf/operation/predicate/RectangleIntersectsPerfTest.java r378 (JTS-1.12)
 *
 **********************************************************************/

#include <geos/geom/PrecisionModel.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/util/GeometricShapeFactory.h>
#include <geos/precision/SimpleGeometryPrecisionReducer.h>
#include <geos/geom/util/SineStarFactory.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/Polygon.h>
#include <geos/profiler.h>
#include <iostream>
#include <vector>
#include <cmath>
#include <sstream>
#include <memory>

using namespace geos::geom;
using namespace geos::io;
using namespace std;

class RectangleIntersectsPerfTest
{
public:
  RectangleIntersectsPerfTest()
    :
    pm(),
    fact(&pm, 0)
  {}

  void test(int nPts)
  {
    double size = 100;
    Coordinate origin(0, 0);
    auto_ptr<Geometry> sinePoly (
      createSineStar(origin, size, nPts)->getBoundary()
    );

    /**
     * Make the geometry "crinkly" by rounding off the points.
     * This defeats the  MonotoneChain optimization in the full relate
     * algorithm, and provides a more realistic test.
     */
    using geos::precision::SimpleGeometryPrecisionReducer;
    PrecisionModel pm(size/10);
    SimpleGeometryPrecisionReducer reducer(&pm);
    auto_ptr<Geometry> sinePolyCrinkly ( reducer.reduce(sinePoly.get()) );
    sinePoly.reset();

    Geometry& target = *sinePolyCrinkly;

    testRectangles(target, 30, 5);
  }

private:

  static const int MAX_ITER = 10;

  static const int NUM_AOI_PTS = 2000;
  static const int NUM_LINES = 5000;
  static const int NUM_LINE_PTS = 1000;

  PrecisionModel pm;
  GeometryFactory fact;

  void testRectangles(const Geometry& target, int nRect, double rectSize)
  {
    vector<const Geometry*> rects;
    createRectangles(*target.getEnvelopeInternal(), nRect, rectSize, rects);
    test(rects, target);
    for (vector<const Geometry*>::iterator i=rects.begin(), n=rects.end();
      i!=n; ++i) delete *i;
  }

  void test(vector<const Geometry*>& rect, const Geometry& g)
  {
    typedef vector<const Geometry*>::size_type size_type;

    stringstream ss; ss << g.getNumPoints() << " pts";

    geos::util::Profile sw(ss.str());
		sw.start();

    for (int i = 0; i < MAX_ITER; i++) {
      for (size_type j = 0; j < rect.size(); j++) {
        rect[j]->intersects(&g);
      }
    }

		sw.stop();
		cout << sw << endl;

  }

  // Push newly created geoms to rectLit
  void createRectangles(const Envelope& env, int nRect, double rectSize,
                        vector<const Geometry*>& rectList)
  {
    int nSide =  1 + (int)sqrt((double) nRect);
    double dx = env.getWidth() / nSide;
    double dy = env.getHeight() / nSide;

    for (int i = 0; i < nSide; i++) {
      for (int j = 0; j < nSide; j++) {
        double baseX = env.getMinX() + i * dx;
        double baseY = env.getMinY() + j * dy;
        Envelope envRect(
            baseX, baseX + dx,
            baseY, baseY + dy);
        Geometry* rect = fact.toGeometry(&envRect);
        rectList.push_back(rect);
      }
    }
  }

  auto_ptr<Polygon> createSineStar(const Coordinate& origin,
                                    double size, int nPts)
  {
      using geos::geom::util::SineStarFactory;

      SineStarFactory gsf(&fact);
      gsf.setCentre(origin);
      gsf.setSize(size);
      gsf.setNumPoints(nPts);
      gsf.setArmLengthRatio(2);
      gsf.setNumArms(20);
      auto_ptr<Polygon> poly = gsf.createSineStar();
      return poly;
  }

};

int
main()
{

  RectangleIntersectsPerfTest tester;

  tester.test(500);
  tester.test(100000);
}

<commit_msg>More concise output from performance tester<commit_after>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2011  Sandro Santilli <strk@keybit.net>
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * Last port: perf/operation/predicate/RectangleIntersectsPerfTest.java r378 (JTS-1.12)
 *
 **********************************************************************/

#include <geos/geom/PrecisionModel.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/util/GeometricShapeFactory.h>
#include <geos/precision/SimpleGeometryPrecisionReducer.h>
#include <geos/geom/util/SineStarFactory.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/Polygon.h>
#include <geos/profiler.h>
#include <iostream>
#include <vector>
#include <cmath>
#include <sstream>
#include <memory>

using namespace geos::geom;
using namespace geos::io;
using namespace std;

class RectangleIntersectsPerfTest
{
public:
  RectangleIntersectsPerfTest()
    :
    pm(),
    fact(&pm, 0)
  {}

  void test(int nPts)
  {
    double size = 100;
    Coordinate origin(0, 0);
    auto_ptr<Geometry> sinePoly (
      createSineStar(origin, size, nPts)->getBoundary()
    );

    /**
     * Make the geometry "crinkly" by rounding off the points.
     * This defeats the  MonotoneChain optimization in the full relate
     * algorithm, and provides a more realistic test.
     */
    using geos::precision::SimpleGeometryPrecisionReducer;
    PrecisionModel pm(size/10);
    SimpleGeometryPrecisionReducer reducer(&pm);
    auto_ptr<Geometry> sinePolyCrinkly ( reducer.reduce(sinePoly.get()) );
    sinePoly.reset();

    Geometry& target = *sinePolyCrinkly;

    testRectangles(target, 30, 5);
  }

private:

  static const int MAX_ITER = 10;

  static const int NUM_AOI_PTS = 2000;
  static const int NUM_LINES = 5000;
  static const int NUM_LINE_PTS = 1000;

  PrecisionModel pm;
  GeometryFactory fact;

  void testRectangles(const Geometry& target, int nRect, double rectSize)
  {
    vector<const Geometry*> rects;
    createRectangles(*target.getEnvelopeInternal(), nRect, rectSize, rects);
    test(rects, target);
    for (vector<const Geometry*>::iterator i=rects.begin(), n=rects.end();
      i!=n; ++i) delete *i;
  }

  void test(vector<const Geometry*>& rect, const Geometry& g)
  {
    typedef vector<const Geometry*>::size_type size_type;

    geos::util::Profile sw("");
		sw.start();

    for (int i = 0; i < MAX_ITER; i++) {
      for (size_type j = 0; j < rect.size(); j++) {
        rect[j]->intersects(&g);
      }
    }

		sw.stop();
		cout << g.getNumPoints() << " points: " << sw.getTot() << " usecs" << endl;

  }

  // Push newly created geoms to rectLit
  void createRectangles(const Envelope& env, int nRect, double rectSize,
                        vector<const Geometry*>& rectList)
  {
    int nSide =  1 + (int)sqrt((double) nRect);
    double dx = env.getWidth() / nSide;
    double dy = env.getHeight() / nSide;

    for (int i = 0; i < nSide; i++) {
      for (int j = 0; j < nSide; j++) {
        double baseX = env.getMinX() + i * dx;
        double baseY = env.getMinY() + j * dy;
        Envelope envRect(
            baseX, baseX + dx,
            baseY, baseY + dy);
        Geometry* rect = fact.toGeometry(&envRect);
        rectList.push_back(rect);
      }
    }
  }

  auto_ptr<Polygon> createSineStar(const Coordinate& origin,
                                    double size, int nPts)
  {
      using geos::geom::util::SineStarFactory;

      SineStarFactory gsf(&fact);
      gsf.setCentre(origin);
      gsf.setSize(size);
      gsf.setNumPoints(nPts);
      gsf.setArmLengthRatio(2);
      gsf.setNumArms(20);
      auto_ptr<Polygon> poly = gsf.createSineStar();
      return poly;
  }

};

int
main()
{

  RectangleIntersectsPerfTest tester;

  tester.test(500);
  tester.test(100000);
}

<|endoftext|>


<commit_before>/*
Copyright (c) 2014, Dilyan Rusev
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "stdafx.h"
#include "Game.h"
#include <cassert>
#include <algorithm>

using namespace std;
using Microsoft::WRL::ComPtr;

Game::Game()
		: APP_TITLE(L"Falling Blocks")
		, APP_CLASS(L"FallingBlocks")
		, WINDOW_WIDTH(1280)
		, WINDOW_HEIGHT(720)
		, BLOCK_WIDTH(35)
		, BLOCK_HEIGHT(35)
		, m_isClassRegistered(false)
		, m_window(nullptr)
		, m_instance(nullptr) {
}

Game::~Game() {
	if (m_isClassRegistered && m_instance) {
		::UnregisterClass(Game::APP_CLASS, m_instance);
	}
}

void Game::Initialize(HINSTANCE instance) {
	assert(instance != nullptr);
	m_instance = instance;

	assert(::QueryPerformanceFrequency(&m_perfFrequency));

	CreateAppWindow();
	InitGraphicsSystems();
	CreateDeviceResources();
}

void Game::InitGraphicsSystems() {
	HRESULT hr = ::CoCreateInstance(CLSID_WICImagingFactory1, nullptr,
		CLSCTX_INPROC_SERVER, __uuidof(m_imageFactory),
		reinterpret_cast<void**>(m_imageFactory.GetAddressOf()));
	assert(SUCCEEDED(hr));

	hr = ::DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(m_writeFactory),
		reinterpret_cast<IUnknown**>(m_writeFactory.GetAddressOf()));
	assert(SUCCEEDED(hr));

	hr = ::D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, IID_PPV_ARGS(&m_drawFactory));
	assert(SUCCEEDED(hr));
}

void Game::CreateAppWindow() {
	assert(m_instance != nullptr);

	WNDCLASSEX wc;
	wc.cbSize = sizeof(wc);
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = nullptr;
	wc.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
	wc.hIcon = ::LoadIcon(nullptr, IDI_APPLICATION);
	wc.hIconSm = ::LoadIcon(nullptr, IDI_APPLICATION);
	wc.hInstance = m_instance;
	wc.lpfnWndProc = &Game::GameProc;
	wc.lpszClassName = Game::APP_CLASS;
	wc.lpszMenuName = nullptr;
	wc.style = 0;

	assert(::RegisterClassEx(&wc));
	m_isClassRegistered = true;

	DWORD windowStyle = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
	DWORD exStyle = 0;
	RECT windowSize = { 0, 0, Game::WINDOW_WIDTH, Game::WINDOW_HEIGHT };
	assert(::AdjustWindowRectEx(&windowSize, windowStyle, FALSE, exStyle));

	int width = windowSize.right - windowSize.left;
	int height = windowSize.bottom - windowSize.top;
	int x = (::GetSystemMetrics(SM_CXSCREEN) - width) / 2;
	int y = (::GetSystemMetrics(SM_CYSCREEN) - height) / 2;

	m_window = ::CreateWindowExW(exStyle, Game::APP_CLASS, Game::APP_TITLE,
		windowStyle, x, y, width, height, HWND_DESKTOP, nullptr, m_instance,
		reinterpret_cast<void*>(this));
	assert(m_window != nullptr);

	m_clientRect.left = 0;
	m_clientRect.right = WINDOW_WIDTH;
	m_clientRect.top = 0;
	m_clientRect.bottom = WINDOW_HEIGHT;

	m_boardPos.x = (WINDOW_WIDTH - m_board.WIDTH * BLOCK_WIDTH) / 2.0f;
	m_boardPos.y = (WINDOW_HEIGHT - m_board.HEIGHT * BLOCK_HEIGHT) / 2.0f;
}

void Game::RunMainLoop() {
	assert(m_instance);
	assert(m_window);

	::ShowWindow(m_window, SW_SHOW);
	::UpdateWindow(m_window);

	MSG msg;
	msg.message = WM_NULL;

	LARGE_INTEGER before, now;
	float elapsedInMs;

	::QueryPerformanceCounter(&before);
	while (msg.message != WM_QUIT) {
		while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}

		::QueryPerformanceCounter(&now);
		elapsedInMs = static_cast<float>((now.QuadPart - before.QuadPart) * 1000 / m_perfFrequency.QuadPart);

		Update(elapsedInMs);
		Render();
	}
}

void Game::Update(float ms) {
	m_board.Update(ms);
}

void Game::Render() {
	m_renderTarget->BeginDraw();
	m_renderTarget->Clear(D2D1::ColorF(D2D1::ColorF::AliceBlue));

	D2D1_RECT_F dest;
	for (int y = 0; y < m_board.HEIGHT; y++) {
		for (int x = 0; x < m_board.WIDTH; x++) {
			auto t = m_board.GetAt(x, y);
			auto& bitmap = m_terimonoBitmaps[t];
			dest.left = m_boardPos.x + static_cast<float>(x * BLOCK_WIDTH);
			dest.top = m_boardPos.y + static_cast<float>(y * BLOCK_HEIGHT);
			dest.right = dest.left + BLOCK_WIDTH;
			dest.bottom = dest.top + BLOCK_HEIGHT;

			m_renderTarget->DrawBitmap(bitmap.Get(), &dest, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
		}
	}

	D2D1_POINT_2F nextOffset = D2D1::Point2F(m_boardPos.x + m_board.WIDTH * BLOCK_WIDTH + 30, m_boardPos.y);
	for (int y = 0; y < m_board.MAX_TETRIMONO_HEIGHT; y++) {
		for (int x = 0; x < m_board.MAX_TETRIMONO_WIDTH; x++) {
			auto t = m_board.GetNextAt(x, y);
			auto& bitmap = m_terimonoBitmaps[t];
			dest.left = nextOffset.x + static_cast<float>(x * BLOCK_WIDTH);
			dest.top = nextOffset.y + static_cast<float>(y * BLOCK_HEIGHT);
			dest.right = dest.left + BLOCK_WIDTH;
			dest.bottom = dest.top + BLOCK_HEIGHT;

			m_renderTarget->DrawBitmap(bitmap.Get(), &dest, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
		}
	}

	if (m_renderTarget->EndDraw() == D2DERR_RECREATE_TARGET) {
		CleanDeviceResources();
		CreateDeviceResources();
	}
}

void Game::CreateDeviceResources() {
	HRESULT hr;
	hr = m_drawFactory->CreateHwndRenderTarget(
		D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(), 96.0f, 96.0f),
		D2D1::HwndRenderTargetProperties(m_window, D2D1::SizeU(WINDOW_WIDTH, WINDOW_HEIGHT)),
		m_renderTarget.ReleaseAndGetAddressOf());
	assert(SUCCEEDED(hr));

	Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solidBrush;
	assert(SUCCEEDED(
		m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Red), &solidBrush)
		));
	solidBrush.As(&m_testBrush);

	m_terimonoBitmaps[Tetrimono_Empty] = LoadImage(L"Assets/block_empty.png");
	m_terimonoBitmaps[Tetrimono_I] = LoadImage(L"Assets/block_blue.png");
	m_terimonoBitmaps[Tetrimono_J] = LoadImage(L"Assets/block_cyan.png");
	m_terimonoBitmaps[Tetrimono_L] = LoadImage(L"Assets/block_green.png");
	m_terimonoBitmaps[Tetrimono_O] = LoadImage(L"Assets/block_orange.png");
	m_terimonoBitmaps[Tetrimono_S] = LoadImage(L"Assets/block_red.png");
	m_terimonoBitmaps[Tetrimono_T] = LoadImage(L"Assets/block_violet.png");
	m_terimonoBitmaps[Tetrimono_Z] = LoadImage(L"Assets/block_yellow.png");
}

ComPtr<ID2D1Bitmap> Game::LoadImage(const wchar_t* fileName) const {
	ComPtr<IWICBitmapDecoder> decoder;
	assert(SUCCEEDED(
		m_imageFactory->CreateDecoderFromFilename(fileName, nullptr, GENERIC_READ,
			WICDecodeMetadataCacheOnDemand, &decoder)
	));

	ComPtr<IWICBitmapFrameDecode> frame;
	assert(SUCCEEDED( decoder->GetFrame(0, &frame) ));

	ComPtr<IWICFormatConverter> formatConverter;
	assert(SUCCEEDED( m_imageFactory->CreateFormatConverter(&formatConverter) ));

	assert(SUCCEEDED(
		formatConverter->Initialize(frame.Get(), GUID_WICPixelFormat32bppPBGRA,
			WICBitmapDitherTypeNone, nullptr, 0.0f, WICBitmapPaletteTypeCustom)
	));

	ComPtr<ID2D1Bitmap> bitmap;
	assert(SUCCEEDED(
		m_renderTarget->CreateBitmapFromWicBitmap(formatConverter.Get(), &bitmap)
	));

	return bitmap;
}

void Game::CleanDeviceResources() {
	m_testBrush = nullptr;
	m_renderTarget = nullptr;
}<commit_msg>fixed timer<commit_after>/*
Copyright (c) 2014, Dilyan Rusev
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "stdafx.h"
#include "Game.h"
#include <cassert>
#include <algorithm>

using namespace std;
using Microsoft::WRL::ComPtr;

Game::Game()
		: APP_TITLE(L"Falling Blocks")
		, APP_CLASS(L"FallingBlocks")
		, WINDOW_WIDTH(1280)
		, WINDOW_HEIGHT(720)
		, BLOCK_WIDTH(35)
		, BLOCK_HEIGHT(35)
		, m_isClassRegistered(false)
		, m_window(nullptr)
		, m_instance(nullptr) {
}

Game::~Game() {
	if (m_isClassRegistered && m_instance) {
		::UnregisterClass(Game::APP_CLASS, m_instance);
	}
}

void Game::Initialize(HINSTANCE instance) {
	assert(instance != nullptr);
	m_instance = instance;

	assert(::QueryPerformanceFrequency(&m_perfFrequency));

	CreateAppWindow();
	InitGraphicsSystems();
	CreateDeviceResources();
}

void Game::InitGraphicsSystems() {
	HRESULT hr = ::CoCreateInstance(CLSID_WICImagingFactory1, nullptr,
		CLSCTX_INPROC_SERVER, __uuidof(m_imageFactory),
		reinterpret_cast<void**>(m_imageFactory.GetAddressOf()));
	assert(SUCCEEDED(hr));

	hr = ::DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(m_writeFactory),
		reinterpret_cast<IUnknown**>(m_writeFactory.GetAddressOf()));
	assert(SUCCEEDED(hr));

	hr = ::D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, IID_PPV_ARGS(&m_drawFactory));
	assert(SUCCEEDED(hr));
}

void Game::CreateAppWindow() {
	assert(m_instance != nullptr);

	WNDCLASSEX wc;
	wc.cbSize = sizeof(wc);
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hbrBackground = nullptr;
	wc.hCursor = ::LoadCursor(nullptr, IDC_ARROW);
	wc.hIcon = ::LoadIcon(nullptr, IDI_APPLICATION);
	wc.hIconSm = ::LoadIcon(nullptr, IDI_APPLICATION);
	wc.hInstance = m_instance;
	wc.lpfnWndProc = &Game::GameProc;
	wc.lpszClassName = Game::APP_CLASS;
	wc.lpszMenuName = nullptr;
	wc.style = 0;

	assert(::RegisterClassEx(&wc));
	m_isClassRegistered = true;

	DWORD windowStyle = WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
	DWORD exStyle = 0;
	RECT windowSize = { 0, 0, Game::WINDOW_WIDTH, Game::WINDOW_HEIGHT };
	assert(::AdjustWindowRectEx(&windowSize, windowStyle, FALSE, exStyle));

	int width = windowSize.right - windowSize.left;
	int height = windowSize.bottom - windowSize.top;
	int x = (::GetSystemMetrics(SM_CXSCREEN) - width) / 2;
	int y = (::GetSystemMetrics(SM_CYSCREEN) - height) / 2;

	m_window = ::CreateWindowExW(exStyle, Game::APP_CLASS, Game::APP_TITLE,
		windowStyle, x, y, width, height, HWND_DESKTOP, nullptr, m_instance,
		reinterpret_cast<void*>(this));
	assert(m_window != nullptr);

	m_clientRect.left = 0;
	m_clientRect.right = WINDOW_WIDTH;
	m_clientRect.top = 0;
	m_clientRect.bottom = WINDOW_HEIGHT;

	m_boardPos.x = (WINDOW_WIDTH - m_board.WIDTH * BLOCK_WIDTH) / 2.0f;
	m_boardPos.y = (WINDOW_HEIGHT - m_board.HEIGHT * BLOCK_HEIGHT) / 2.0f;
}

void Game::RunMainLoop() {
	assert(m_instance);
	assert(m_window);

	::ShowWindow(m_window, SW_SHOW);
	::UpdateWindow(m_window);

	MSG msg;
	msg.message = WM_NULL;

	LARGE_INTEGER before, now;
	float elapsedInMs;

	::QueryPerformanceCounter(&before);
	while (msg.message != WM_QUIT) {
		while (::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}

		::QueryPerformanceCounter(&now);
		elapsedInMs = static_cast<float>((now.QuadPart - before.QuadPart) * 1000 / m_perfFrequency.QuadPart);

		Update(elapsedInMs);
		Render();
		before = now;
	}
}

void Game::Update(float ms) {
	m_board.Update(ms);
}

void Game::Render() {
	m_renderTarget->BeginDraw();
	m_renderTarget->Clear(D2D1::ColorF(D2D1::ColorF::AliceBlue));

	D2D1_RECT_F dest;
	for (int y = 0; y < m_board.HEIGHT; y++) {
		for (int x = 0; x < m_board.WIDTH; x++) {
			auto t = m_board.GetAt(x, y);
			auto& bitmap = m_terimonoBitmaps[t];
			dest.left = m_boardPos.x + static_cast<float>(x * BLOCK_WIDTH);
			dest.top = m_boardPos.y + static_cast<float>(y * BLOCK_HEIGHT);
			dest.right = dest.left + BLOCK_WIDTH;
			dest.bottom = dest.top + BLOCK_HEIGHT;

			m_renderTarget->DrawBitmap(bitmap.Get(), &dest, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
		}
	}

	D2D1_POINT_2F nextOffset = D2D1::Point2F(m_boardPos.x + m_board.WIDTH * BLOCK_WIDTH + 30, m_boardPos.y);
	for (int y = 0; y < m_board.MAX_TETRIMONO_HEIGHT; y++) {
		for (int x = 0; x < m_board.MAX_TETRIMONO_WIDTH; x++) {
			auto t = m_board.GetNextAt(x, y);
			auto& bitmap = m_terimonoBitmaps[t];
			dest.left = nextOffset.x + static_cast<float>(x * BLOCK_WIDTH);
			dest.top = nextOffset.y + static_cast<float>(y * BLOCK_HEIGHT);
			dest.right = dest.left + BLOCK_WIDTH;
			dest.bottom = dest.top + BLOCK_HEIGHT;

			m_renderTarget->DrawBitmap(bitmap.Get(), &dest, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
		}
	}

	if (m_renderTarget->EndDraw() == D2DERR_RECREATE_TARGET) {
		CleanDeviceResources();
		CreateDeviceResources();
	}
}

void Game::CreateDeviceResources() {
	HRESULT hr;
	hr = m_drawFactory->CreateHwndRenderTarget(
		D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(), 96.0f, 96.0f),
		D2D1::HwndRenderTargetProperties(m_window, D2D1::SizeU(WINDOW_WIDTH, WINDOW_HEIGHT)),
		m_renderTarget.ReleaseAndGetAddressOf());
	assert(SUCCEEDED(hr));

	Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solidBrush;
	assert(SUCCEEDED(
		m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Red), &solidBrush)
		));
	solidBrush.As(&m_testBrush);

	m_terimonoBitmaps[Tetrimono_Empty] = LoadImage(L"Assets/block_empty.png");
	m_terimonoBitmaps[Tetrimono_I] = LoadImage(L"Assets/block_blue.png");
	m_terimonoBitmaps[Tetrimono_J] = LoadImage(L"Assets/block_cyan.png");
	m_terimonoBitmaps[Tetrimono_L] = LoadImage(L"Assets/block_green.png");
	m_terimonoBitmaps[Tetrimono_O] = LoadImage(L"Assets/block_orange.png");
	m_terimonoBitmaps[Tetrimono_S] = LoadImage(L"Assets/block_red.png");
	m_terimonoBitmaps[Tetrimono_T] = LoadImage(L"Assets/block_violet.png");
	m_terimonoBitmaps[Tetrimono_Z] = LoadImage(L"Assets/block_yellow.png");
}

ComPtr<ID2D1Bitmap> Game::LoadImage(const wchar_t* fileName) const {
	ComPtr<IWICBitmapDecoder> decoder;
	assert(SUCCEEDED(
		m_imageFactory->CreateDecoderFromFilename(fileName, nullptr, GENERIC_READ,
			WICDecodeMetadataCacheOnDemand, &decoder)
	));

	ComPtr<IWICBitmapFrameDecode> frame;
	assert(SUCCEEDED( decoder->GetFrame(0, &frame) ));

	ComPtr<IWICFormatConverter> formatConverter;
	assert(SUCCEEDED( m_imageFactory->CreateFormatConverter(&formatConverter) ));

	assert(SUCCEEDED(
		formatConverter->Initialize(frame.Get(), GUID_WICPixelFormat32bppPBGRA,
			WICBitmapDitherTypeNone, nullptr, 0.0f, WICBitmapPaletteTypeCustom)
	));

	ComPtr<ID2D1Bitmap> bitmap;
	assert(SUCCEEDED(
		m_renderTarget->CreateBitmapFromWicBitmap(formatConverter.Get(), &bitmap)
	));

	return bitmap;
}

void Game::CleanDeviceResources() {
	m_testBrush = nullptr;
	m_renderTarget = nullptr;
}<|endoftext|>


<commit_before>//****************************************************************************
// Copyright © 2011, Jan Erik Breimo.
// Created 2011-07-14 by Jan Erik Breimo
//
// This file is distributed under the Simplified BSD License.
// License text is included with the source distribution.
//****************************************************************************
#include <algorithm>
#include <cassert>

namespace Ystring { namespace Encodings
{
    namespace Detail
    {
        static inline bool isContinuation(uint8_t c)
        {
            return (c & 0xC0) == 0x80;
        }

        static inline bool isAscii(char32_t c)
        {
            return  (c & 0x80) == 0;
        }

        template<typename FwdIt>
        FwdIt findEndOfCodePoint(FwdIt begin, FwdIt end)
        {
            while (begin != end && isContinuation(*begin))
                ++begin;
            return begin;
        }
    }

    template<typename FwdIt>
    std::tuple<FwdIt, FwdIt, DecoderResult_t> nextInvalidUtf8CodePoint(
            FwdIt begin, FwdIt end)
    {
        for (auto it = begin; it != end; ++it)
        {
            if (Detail::isAscii(*it))
                continue;

            if (Detail::isContinuation(*it))
            {
                return std::make_tuple(
                        it, Detail::findEndOfCodePoint(it, end),
                        DecoderResult::INVALID);
            }

            auto first = it;
            auto bits = *it;
            auto bit = 0x40u;
            while (bit & bits)
            {
                if (++it == end)
                {
                    return std::make_tuple(
                            first, it, DecoderResult::INCOMPLETE);
                }
                if (!Detail::isContinuation(*it))
                    return std::make_tuple(first, it, DecoderResult::INVALID);
                bit >>= 1;
            }
            if (((bits & 0xFC) ^ 0xFC) < 0xC)
                return std::make_tuple(first, it, DecoderResult::INVALID);
        }

        return std::make_tuple(end, end, DecoderResult::OK);
    }

    template<typename FwdIt>
    bool isValidUtf8(FwdIt begin, FwdIt end, bool acceptIncomplete)
    {
        auto tuple = nextInvalidUtf8CodePoint(begin, end);
        auto result = std::get<2>(tuple);
        if (result == DecoderResult::OK)
            return true;
        return result == DecoderResult::OK
            || (result == DecoderResult::INCOMPLETE && acceptIncomplete);
    }

    template <typename FwdIt>
    DecoderResult_t nextUtf8CodePoint(char32_t& codePoint,
                                      FwdIt& it, FwdIt end)
    {
        if (it == end)
            return DecoderResult::END_OF_STRING;

        if (Detail::isAscii(*it))
        {
            codePoint = (uint8_t)*it++;
            return DecoderResult::OK;
        }

        if (Detail::isContinuation(*it) || uint8_t(*it) >= 0xFE)
            return DecoderResult::INVALID;

        size_t count = 1;
        unsigned bit = 0x20;
        codePoint = *it & 0x3F;
        while (codePoint & bit)
        {
            bit >>= 1;
            ++count;
        }

        codePoint &= bit - 1;

        FwdIt initialIt = it;
        while (++it != end && count && Detail::isContinuation(*it))
        {
            codePoint <<= 6;
            codePoint |= *it & 0x3F;
            --count;
        }

        if (count)
        {
            auto incomplete = it == end;
            it = initialIt;
            return incomplete ? DecoderResult::INCOMPLETE
                              : DecoderResult::INVALID;
        }

        return DecoderResult::OK;
    }

    template <typename BiIt>
    DecoderResult_t prevUtf8CodePoint(char32_t& codePoint,
                                      BiIt begin, BiIt& it)
    {
        if (it == begin)
            return DecoderResult::END_OF_STRING;

        BiIt initialIt = it;
        --it;
        if (Detail::isAscii(*it))
        {
            codePoint = (uint8_t)*it;
            return DecoderResult::OK;
        }

        codePoint = 0;
        uint8_t mask = 0xC0;
        uint8_t bit = 0x20;
        char32_t shift = 0;
        while (Detail::isContinuation(*it))
        {
            if (bit == 1 || it == begin)
            {
                it = initialIt;
                return DecoderResult::INVALID;
            }
            mask |= bit;
            bit >>= 1;
            codePoint |= char32_t(*it & 0x3F) << shift;
            shift += 6;
            --it;
        }

        uint8_t byte = *it;
        if ((byte & mask) != uint8_t(mask << 1))
        {
            it = initialIt;
            if ((byte & mask) != mask)
                return DecoderResult::INVALID;
            else
                return DecoderResult::INCOMPLETE;
        }

        codePoint |= (byte & ~mask) << shift;

        return DecoderResult::OK;
    }

    template <typename FwdIt>
    bool skipNextUtf8CodePoint(FwdIt& it, FwdIt end, size_t count)
    {
        for (auto i = 0u; i < count; ++i)
        {
            if (it == end)
                return false;
            do
            {
                ++it;
            }
            while (it != end && Detail::isContinuation(*it));
        }

        return true;
    }

    template <typename BiIt>
    bool skipPrevUtf8CodePoint(BiIt begin, BiIt& it, size_t count)
    {
        for (auto i = 0u; i < count; ++i)
        {
            if (it == begin)
                return false;
            do
            {
                --it;
            }
            while (it != begin && Detail::isContinuation(*it));
        }

        return true;
    }
}}
<commit_msg>Minor improvements.<commit_after>//****************************************************************************
// Copyright © 2011, Jan Erik Breimo.
// Created 2011-07-14 by Jan Erik Breimo
//
// This file is distributed under the Simplified BSD License.
// License text is included with the source distribution.
//****************************************************************************
#include <algorithm>
#include <cassert>

namespace Ystring { namespace Encodings
{
    namespace Detail
    {
        static inline bool isContinuation(uint8_t c)
        {
            return (c & 0xC0u) == 0x80;
        }

        static inline bool isAscii(char32_t c)
        {
            return  (c & 0x80u) == 0;
        }

        template<typename FwdIt>
        FwdIt findEndOfCodePoint(FwdIt begin, FwdIt end)
        {
            while (begin != end && isContinuation(*begin))
                ++begin;
            return begin;
        }
    }

    template<typename FwdIt>
    std::tuple<FwdIt, FwdIt, DecoderResult_t> nextInvalidUtf8CodePoint(
            FwdIt begin, FwdIt end)
    {
        for (auto it = begin; it != end; ++it)
        {
            if (Detail::isAscii(*it))
                continue;

            if (Detail::isContinuation(*it))
            {
                return std::make_tuple(
                        it, Detail::findEndOfCodePoint(it, end),
                        DecoderResult::INVALID);
            }

            auto first = it;
            auto bits = *it;
            auto bit = 0x40u;
            while (bit & bits)
            {
                if (++it == end)
                {
                    return std::make_tuple(
                            first, it, DecoderResult::INCOMPLETE);
                }
                if (!Detail::isContinuation(*it))
                    return std::make_tuple(first, it, DecoderResult::INVALID);
                bit >>= 1u;
            }
            if (((bits & 0xFC) ^ 0xFC) < 0xC)
                return std::make_tuple(first, it, DecoderResult::INVALID);
        }

        return std::make_tuple(end, end, DecoderResult::OK);
    }

    template<typename FwdIt>
    bool isValidUtf8(FwdIt begin, FwdIt end, bool acceptIncomplete)
    {
        auto tuple = nextInvalidUtf8CodePoint(begin, end);
        auto result = std::get<2>(tuple);
        return result == DecoderResult::OK
            || (result == DecoderResult::INCOMPLETE && acceptIncomplete);
    }

    template <typename FwdIt>
    DecoderResult_t nextUtf8CodePoint(char32_t& codePoint,
                                      FwdIt& it, FwdIt end)
    {
        if (it == end)
            return DecoderResult::END_OF_STRING;

        if (Detail::isAscii(*it))
        {
            codePoint = uint8_t(*it++);
            return DecoderResult::OK;
        }

        if (Detail::isContinuation(*it) || uint8_t(*it) >= 0xFE)
            return DecoderResult::INVALID;

        size_t count = 1;
        unsigned bit = 0x20;
        codePoint = *it & 0x3F;
        while (codePoint & bit)
        {
            bit >>= 1u;
            ++count;
        }

        codePoint &= bit - 1;

        FwdIt initialIt = it;
        while (++it != end && count && Detail::isContinuation(*it))
        {
            codePoint <<= 6u;
            codePoint |= *it & 0x3F;
            --count;
        }

        if (count)
        {
            auto incomplete = it == end;
            it = initialIt;
            return incomplete ? DecoderResult::INCOMPLETE
                              : DecoderResult::INVALID;
        }

        return DecoderResult::OK;
    }

    template <typename BiIt>
    DecoderResult_t prevUtf8CodePoint(char32_t& codePoint,
                                      BiIt begin, BiIt& it)
    {
        if (it == begin)
            return DecoderResult::END_OF_STRING;

        BiIt initialIt = it;
        --it;
        if (Detail::isAscii(*it))
        {
            codePoint = (uint8_t)*it;
            return DecoderResult::OK;
        }

        codePoint = 0;
        uint8_t mask = 0xC0;
        uint8_t bit = 0x20;
        char32_t shift = 0;
        while (Detail::isContinuation(*it))
        {
            if (bit == 1 || it == begin)
            {
                it = initialIt;
                return DecoderResult::INVALID;
            }
            mask |= bit;
            bit >>= 1u;
            codePoint |= char32_t(*it & 0x3F) << shift;
            shift += 6;
            --it;
        }

        uint8_t byte = *it;
        if ((byte & mask) != uint8_t(mask << 1u))
        {
            it = initialIt;
            if ((byte & mask) != mask)
                return DecoderResult::INVALID;
            else
                return DecoderResult::INCOMPLETE;
        }

        codePoint |= char32_t(byte & ~mask) << shift;

        return DecoderResult::OK;
    }

    template <typename FwdIt>
    bool skipNextUtf8CodePoint(FwdIt& it, FwdIt end, size_t count)
    {
        for (auto i = 0u; i < count; ++i)
        {
            if (it == end)
                return false;
            do
            {
                ++it;
            }
            while (it != end && Detail::isContinuation(*it));
        }

        return true;
    }

    template <typename BiIt>
    bool skipPrevUtf8CodePoint(BiIt begin, BiIt& it, size_t count)
    {
        for (auto i = 0u; i < count; ++i)
        {
            if (it == begin)
                return false;
            do
            {
                --it;
            }
            while (it != begin && Detail::isContinuation(*it));
        }

        return true;
    }
}}
<|endoftext|>


<commit_before>/*
 * ModSecurity, http://www.modsecurity.org/
 * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * You may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address security@modsecurity.org.
 *
 */

#include "actions/transformations/css_decode.h"

#include <string.h>

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

#include "modsecurity/assay.h"
#include "actions/transformations/transformation.h"
#include "src/utils.h"

namespace ModSecurity {
namespace actions {
namespace transformations {

std::string CssDecode::evaluate(std::string value,
    Assay *assay) {
    char *tmp = strdup(value.c_str());
    css_decode_inplace((unsigned char *)tmp, value.size());
    std::string ret(tmp, 0, value.size());
    free(tmp);
    return ret;
}

}  // namespace transformations
}  // namespace actions
}  // namespace ModSecurity
<commit_msg>Fix cssDecode transformation<commit_after>/*
 * ModSecurity, http://www.modsecurity.org/
 * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/)
 *
 * You may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * If any of the files related to licensing are missing or if you have any
 * other questions related to licensing please contact Trustwave Holdings, Inc.
 * directly using the email address security@modsecurity.org.
 *
 */

#include "actions/transformations/css_decode.h"

#include <string.h>

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

#include "modsecurity/assay.h"
#include "actions/transformations/transformation.h"
#include "src/utils.h"

namespace ModSecurity {
namespace actions {
namespace transformations {

std::string CssDecode::evaluate(std::string value,
    Assay *assay) {

    char *tmp = (char *) malloc(sizeof(char) * value.size() + 1);
    memcpy(tmp, value.c_str(), value.size() + 1);
    tmp[value.size()] = '\0';

    css_decode_inplace((unsigned char *)tmp, value.size());
    std::string ret(tmp, 0, value.size());
    free(tmp);
    return ret;
}

}  // namespace transformations
}  // namespace actions
}  // namespace ModSecurity
<|endoftext|>


<commit_before>#ifndef CONTEXT_HPP_
#define CONTEXT_HPP_

#include <string>
#include <atomic>
#include <memory>
#include <thread>
#include <cstdio>
#include <mutex>

template<typename T>
class AtomicWrapper {

	mutable std::mutex lock;

	T value;

public:

	template<typename U>
	AtomicWrapper(U&& u) : lock() {
		std::lock_guard<decltype(lock)>(lock);
		value = T(u);
	}

	template<typename U>
	AtomicWrapper& operator=(U&& newValue) {
		std::lock_guard<decltype(lock)>(lock);
		value = std::forward<U>(newValue);
	}

	operator T() const {
		std::lock_guard<decltype(lock)>(lock);
		T ret = value;
		return ret;
	}

};

std::string runCommand(std::string command) {
	std::FILE* pipe = popen(command.c_str(), "r");

	if(!pipe) return "";

	char buffer[128];

	std::string result;

	while(!std::feof(pipe)) {
		std::fgets(buffer, sizeof(buffer), pipe);
		result += buffer;
	}
	pclose(pipe);
	return result;
}

class Context: std::enable_shared_from_this<Context> {
	std::atomic_bool isRunning;
	std::string cwd;

	std::atomic<std::shared_ptr<std::string>> currentResult;

public:

	Context() {
		isRunning.store(false);
		currentResult.store(std::make_shared<std::string>(""));
	}

	void setCwd(std::string c) { cwd = std::move(c); }
	const std::string& getCwd() const { return cwd; }

	void run() {
		isRunning = true;
		std::thread t(
				[&](){
					currentResult.store(std::make_shared<std::string>(runCommand("ls -la")));
				}
		);
	}

	void stop() {
		isRunning = false;
	}

	std::string getResult() const {
		return *currentResult.load();
	}

};

#endif /* CONTEXT_HPP_ */
<commit_msg>Replace std::atomics with AtomicWrapper<commit_after>#ifndef CONTEXT_HPP_
#define CONTEXT_HPP_

#include <string>
#include <atomic>
#include <memory>
#include <thread>
#include <cstdio>
#include <mutex>

template<typename T>
class AtomicWrapper {

	mutable std::mutex lock;

	T value;

public:

	template<typename U>
	AtomicWrapper(U&& u) : lock() {
		std::lock_guard<decltype(lock)> g(lock);
		value = T(u);
	}

	template<typename U>
	AtomicWrapper& operator=(U&& newValue) {
		std::lock_guard<decltype(lock)> g(lock);
		value = std::forward<U>(newValue);
		return *this;
	}

	operator T() const {
		std::lock_guard<decltype(lock)> g(lock);
		T ret = value;
		return ret;
	}

};

std::string runCommand(std::string command) {
	std::FILE* pipe = popen(command.c_str(), "r");

	if(!pipe) return "";

	char buffer[128];

	std::string result;

	while(!std::feof(pipe)) {
		std::fgets(buffer, sizeof(buffer), pipe);
		result += buffer;
	}
	pclose(pipe);
	return result;
}

class Context: std::enable_shared_from_this<Context> {
	std::atomic_bool isRunning;
	std::string cwd;

	AtomicWrapper<std::string> currentResult = "";

public:

	Context() {
		isRunning.store(false);
	}

	void setCwd(std::string c) { cwd = std::move(c); }
	const std::string& getCwd() const { return cwd; }

	void run() {
		isRunning = true;
		std::thread t(
				[&](){
					currentResult = runCommand("ls -la");
				}
		);
	}

	void stop() {
		isRunning = false;
	}

	std::string getResult() const {
		return currentResult;
	}

};

#endif /* CONTEXT_HPP_ */
<|endoftext|>