<commit_before>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "CameraCalc.h"
#include "JsonHelper.h"
#include "Vehicle.h"
#include "CameraMetaData.h"

#include <QQmlEngine>

const char* CameraCalc::cameraNameName =                    "CameraName";
const char* CameraCalc::valueSetIsDistanceName =            "ValueSetIsDistance";
const char* CameraCalc::distanceToSurfaceName =             "DistanceToSurface";
const char* CameraCalc::distanceToSurfaceRelativeName =     "DistanceToSurfaceRelative";
const char* CameraCalc::imageDensityName =                  "ImageDensity";
const char* CameraCalc::frontalOverlapName =                "FrontalOverlap";
const char* CameraCalc::sideOverlapName =                   "SideOverlap";
const char* CameraCalc::adjustedFootprintFrontalName =      "AdjustedFootprintFrontal";
const char* CameraCalc::adjustedFootprintSideName =         "AdjustedFootprintSide";

const char* CameraCalc::_jsonCameraSpecTypeKey =            "CameraSpecType";

CameraCalc::CameraCalc(Vehicle* vehicle, const QString& settingsGroup, QObject* parent)
    : CameraSpec                    (settingsGroup, parent)
    , _vehicle                      (vehicle)
    , _dirty                        (false)
    , _disableRecalc                (false)
    , _distanceToSurfaceRelative    (true)
    , _metaDataMap                  (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraCalc.FactMetaData.json"), this))
    , _cameraNameFact               (settingsGroup, _metaDataMap[cameraNameName])
    , _valueSetIsDistanceFact       (settingsGroup, _metaDataMap[valueSetIsDistanceName])
    , _distanceToSurfaceFact        (settingsGroup, _metaDataMap[distanceToSurfaceName])
    , _imageDensityFact             (settingsGroup, _metaDataMap[imageDensityName])
    , _frontalOverlapFact           (settingsGroup, _metaDataMap[frontalOverlapName])
    , _sideOverlapFact              (settingsGroup, _metaDataMap[sideOverlapName])
    , _adjustedFootprintSideFact    (settingsGroup, _metaDataMap[adjustedFootprintSideName])
    , _adjustedFootprintFrontalFact (settingsGroup, _metaDataMap[adjustedFootprintFrontalName])
    , _imageFootprintSide           (0)
    , _imageFootprintFrontal        (0)
    , _knownCameraList              (_vehicle->staticCameraList())
{
    QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);

    connect(&_valueSetIsDistanceFact,       &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_distanceToSurfaceFact,        &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_imageDensityFact,             &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_frontalOverlapFact,           &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_sideOverlapFact,              &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_adjustedFootprintSideFact,    &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_adjustedFootprintFrontalFact, &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(this,                           &CameraCalc::distanceToSurfaceRelativeChanged,  this, &CameraCalc::_setDirty);

    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::_cameraNameChanged);
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::isManualCameraChanged);
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::isCustomCameraChanged);

    connect(&_distanceToSurfaceFact,    &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(&_imageDensityFact,         &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(&_frontalOverlapFact,       &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(&_sideOverlapFact,          &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(sensorWidth(),              &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(sensorHeight(),             &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(imageWidth(),               &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(imageHeight(),              &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(focalLength(),              &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(landscape(),                &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);

    _cameraNameChanged();

    setDirty(false);
}

void CameraCalc::setDirty(bool dirty)
{
    if (_dirty != dirty) {
        _dirty = dirty;
        emit dirtyChanged(_dirty);
    }
}

void CameraCalc::_cameraNameChanged(void)
{
    if (_disableRecalc) {
        return;
    }

    QString cameraName = _cameraNameFact.rawValue().toString();

    // Validate known camera name
    bool foundKnownCamera = false;
    CameraMetaData* cameraMetaData = NULL;
    if (!isManualCamera() && !isCustomCamera()) {
        for (int cameraIndex=0; cameraIndex<_knownCameraList.count(); cameraIndex++) {
            cameraMetaData = _knownCameraList[cameraIndex].value<CameraMetaData*>();
            if (cameraName == cameraMetaData->name()) {
                foundKnownCamera = true;
                break;
            }
        }

        if (!foundKnownCamera) {
            // This will cause another camera changed signal which will recurse back to this routine
            _cameraNameFact.setRawValue(customCameraName());
            return;
        }
    }

    _disableRecalc = true;
    if (foundKnownCamera) {
        sensorWidth()->setRawValue          (cameraMetaData->sensorWidth());
        sensorHeight()->setRawValue         (cameraMetaData->sensorHeight());
        imageWidth()->setRawValue           (cameraMetaData->imageWidth());
        imageHeight()->setRawValue          (cameraMetaData->imageHeight());
        focalLength()->setRawValue          (cameraMetaData->focalLength());
        landscape()->setRawValue            (cameraMetaData->landscape());
        fixedOrientation()->setRawValue     (cameraMetaData->fixedOrientation());
        minTriggerInterval()->setRawValue   (cameraMetaData->minTriggerInterval());
    } else {
        if (isManualCamera() || isCustomCamera()) {
            // These values are unknown for these types
            fixedOrientation()->setRawValue(false);
            minTriggerInterval()->setRawValue(0);
            if (isManualCamera()) {
                valueSetIsDistance()->setRawValue(false);
            }
        } else {
            qWarning() << "Internal Error: Not known camera, but now manual or custom either";
        }
    }
    _disableRecalc = false;

    _recalcTriggerDistance();
    _adjustDistanceToSurfaceRelative();
}

void CameraCalc::_recalcTriggerDistance(void)
{
    if (_disableRecalc || isManualCamera()) {
        return;
    }

    _disableRecalc = true;

    double focalLength =    this->focalLength()->rawValue().toDouble();
    double sensorWidth =    this->sensorWidth()->rawValue().toDouble();
    double sensorHeight =   this->sensorHeight()->rawValue().toDouble();
    double imageWidth =     this->imageWidth()->rawValue().toDouble();
    double imageHeight =    this->imageHeight()->rawValue().toDouble();
    double imageDensity =   _imageDensityFact.rawValue().toDouble();

    if (focalLength <= 0 || sensorWidth <= 0 || sensorHeight <= 0 || imageWidth <= 0 || imageHeight <= 0 || imageDensity <= 0) {
        return;
    }

    if (_valueSetIsDistanceFact.rawValue().toBool()) {
        _imageDensityFact.setRawValue((_distanceToSurfaceFact.rawValue().toDouble() * sensorWidth * 100.0) / (imageWidth * focalLength));
    } else {
        _distanceToSurfaceFact.setRawValue((imageWidth * _imageDensityFact.rawValue().toDouble() * focalLength) / (sensorWidth * 100.0));
    }

    imageDensity = _imageDensityFact.rawValue().toDouble();

    if (landscape()->rawValue().toBool()) {
        _imageFootprintSide =       (imageWidth  * imageDensity) / 100.0;
        _imageFootprintFrontal =    (imageHeight * imageDensity) / 100.0;
    } else {
        _imageFootprintSide  =      (imageHeight * imageDensity) / 100.0;
        _imageFootprintFrontal =    (imageWidth  * imageDensity) / 100.0;
    }
    _adjustedFootprintSideFact.setRawValue      (_imageFootprintSide * ((100.0 - _sideOverlapFact.rawValue().toDouble()) / 100.0));
    _adjustedFootprintFrontalFact.setRawValue   (_imageFootprintFrontal * ((100.0 - _frontalOverlapFact.rawValue().toDouble()) / 100.0));

    emit imageFootprintSideChanged      (_imageFootprintSide);
    emit imageFootprintFrontalChanged   (_imageFootprintFrontal);

    _disableRecalc = false;
}

void CameraCalc::save(QJsonObject& json) const
{
    json[JsonHelper::jsonVersionKey] =      1;
    json[adjustedFootprintSideName] =       _adjustedFootprintSideFact.rawValue().toDouble();
    json[adjustedFootprintFrontalName] =    _adjustedFootprintFrontalFact.rawValue().toDouble();
    json[distanceToSurfaceName] =           _distanceToSurfaceFact.rawValue().toDouble();
    json[distanceToSurfaceRelativeName] =   _distanceToSurfaceRelative;
    json[cameraNameName] =                  _cameraNameFact.rawValue().toString();

    if (!isManualCamera()) {
        CameraSpec::save(json);
        json[valueSetIsDistanceName] = _valueSetIsDistanceFact.rawValue().toBool();
        json[imageDensityName] =       _imageDensityFact.rawValue().toDouble();
        json[frontalOverlapName] =     _frontalOverlapFact.rawValue().toDouble();
        json[sideOverlapName] =        _sideOverlapFact.rawValue().toDouble();
    }
}

bool CameraCalc::load(const QJsonObject& json, QString& errorString)
{
    QJsonObject v1Json = json;

    if (!v1Json.contains(JsonHelper::jsonVersionKey)) {
        // Version 0 file. Differences from Version 1 for conversion:
        //  JsonHelper::jsonVersionKey not stored
        //  _jsonCameraSpecTypeKey stores CameraSpecType
        //  _jsonCameraNameKey only set if CameraSpecKnown
        int cameraSpec = v1Json[_jsonCameraSpecTypeKey].toInt(CameraSpecNone);
        if (cameraSpec == CameraSpecCustom) {
            v1Json[cameraNameName] = customCameraName();
        } else if (cameraSpec == CameraSpecNone) {
            v1Json[cameraNameName] = manualCameraName();
        }
        v1Json.remove(_jsonCameraSpecTypeKey);
        v1Json[JsonHelper::jsonVersionKey] = 1;
    }

    int version = v1Json[JsonHelper::jsonVersionKey].toInt();
    if (version != 1) {
        errorString = tr("CameraCalc section version %1 not supported").arg(version);
        return false;
    }

    QList<JsonHelper::KeyValidateInfo> keyInfoList1 = {
        { cameraNameName,                   QJsonValue::String, true },
        { adjustedFootprintSideName,        QJsonValue::Double, true },
        { adjustedFootprintFrontalName,     QJsonValue::Double, true },
        { distanceToSurfaceName,            QJsonValue::Double, true },
        { distanceToSurfaceRelativeName,    QJsonValue::Bool, true },
    };
    if (!JsonHelper::validateKeys(v1Json, keyInfoList1, errorString)) {
        return false;
    }

    _disableRecalc = true;

    _cameraNameFact.setRawValue                 (v1Json[cameraNameName].toString());
    _adjustedFootprintSideFact.setRawValue      (v1Json[adjustedFootprintSideName].toDouble());
    _adjustedFootprintFrontalFact.setRawValue   (v1Json[adjustedFootprintFrontalName].toDouble());
    _distanceToSurfaceFact.setRawValue          (v1Json[distanceToSurfaceName].toDouble());

    _distanceToSurfaceRelative = v1Json[distanceToSurfaceRelativeName].toBool();

    if (!isManualCamera()) {
        QList<JsonHelper::KeyValidateInfo> keyInfoList2 = {
            { valueSetIsDistanceName,   QJsonValue::Bool,   true },
            { imageDensityName,         QJsonValue::Double, true },
            { frontalOverlapName,       QJsonValue::Double, true },
            { sideOverlapName,          QJsonValue::Double, true },
        };
        if (!JsonHelper::validateKeys(v1Json, keyInfoList2, errorString)) {
            _disableRecalc = false;
            return false;
        }

        _valueSetIsDistanceFact.setRawValue (v1Json[valueSetIsDistanceName].toBool());
        _imageDensityFact.setRawValue       (v1Json[imageDensityName].toDouble());
        _frontalOverlapFact.setRawValue     (v1Json[frontalOverlapName].toDouble());
        _sideOverlapFact.setRawValue        (v1Json[sideOverlapName].toDouble());

        if (!CameraSpec::load(v1Json, errorString)) {
            return false;
        }
    }

    _disableRecalc = false;

    return true;
}

QString CameraCalc::customCameraName(void)
{
    return tr("Custom Camera");
}

QString CameraCalc::manualCameraName(void)
{
    return tr("Manual (no camera specs)");
}

void CameraCalc::_adjustDistanceToSurfaceRelative(void)
{
    if (!isManualCamera()) {
        setDistanceToSurfaceRelative(true);
    }
}

void CameraCalc::setDistanceToSurfaceRelative(bool distanceToSurfaceRelative)
{
    if (distanceToSurfaceRelative != _distanceToSurfaceRelative) {
        _distanceToSurfaceRelative = distanceToSurfaceRelative;
        emit distanceToSurfaceRelativeChanged(distanceToSurfaceRelative);
    }
}

void CameraCalc::_setDirty(void)
{
    setDirty(true);
}
<commit_msg><commit_after>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "CameraCalc.h"
#include "JsonHelper.h"
#include "Vehicle.h"
#include "CameraMetaData.h"

#include <QQmlEngine>

const char* CameraCalc::cameraNameName =                    "CameraName";
const char* CameraCalc::valueSetIsDistanceName =            "ValueSetIsDistance";
const char* CameraCalc::distanceToSurfaceName =             "DistanceToSurface";
const char* CameraCalc::distanceToSurfaceRelativeName =     "DistanceToSurfaceRelative";
const char* CameraCalc::imageDensityName =                  "ImageDensity";
const char* CameraCalc::frontalOverlapName =                "FrontalOverlap";
const char* CameraCalc::sideOverlapName =                   "SideOverlap";
const char* CameraCalc::adjustedFootprintFrontalName =      "AdjustedFootprintFrontal";
const char* CameraCalc::adjustedFootprintSideName =         "AdjustedFootprintSide";

const char* CameraCalc::_jsonCameraSpecTypeKey =            "CameraSpecType";

CameraCalc::CameraCalc(Vehicle* vehicle, const QString& settingsGroup, QObject* parent)
    : CameraSpec                    (settingsGroup, parent)
    , _vehicle                      (vehicle)
    , _dirty                        (false)
    , _disableRecalc                (false)
    , _distanceToSurfaceRelative    (true)
    , _metaDataMap                  (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraCalc.FactMetaData.json"), this))
    , _cameraNameFact               (settingsGroup, _metaDataMap[cameraNameName])
    , _valueSetIsDistanceFact       (settingsGroup, _metaDataMap[valueSetIsDistanceName])
    , _distanceToSurfaceFact        (settingsGroup, _metaDataMap[distanceToSurfaceName])
    , _imageDensityFact             (settingsGroup, _metaDataMap[imageDensityName])
    , _frontalOverlapFact           (settingsGroup, _metaDataMap[frontalOverlapName])
    , _sideOverlapFact              (settingsGroup, _metaDataMap[sideOverlapName])
    , _adjustedFootprintSideFact    (settingsGroup, _metaDataMap[adjustedFootprintSideName])
    , _adjustedFootprintFrontalFact (settingsGroup, _metaDataMap[adjustedFootprintFrontalName])
    , _imageFootprintSide           (0)
    , _imageFootprintFrontal        (0)
    , _knownCameraList              (_vehicle->staticCameraList())
{
    QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);

    connect(&_valueSetIsDistanceFact,       &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_distanceToSurfaceFact,        &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_imageDensityFact,             &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_frontalOverlapFact,           &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_sideOverlapFact,              &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_adjustedFootprintSideFact,    &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_adjustedFootprintFrontalFact, &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
    connect(this,                           &CameraCalc::distanceToSurfaceRelativeChanged,  this, &CameraCalc::_setDirty);

    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::_cameraNameChanged);
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::isManualCameraChanged);
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::isCustomCameraChanged);

    connect(&_distanceToSurfaceFact,    &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(&_imageDensityFact,         &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(&_frontalOverlapFact,       &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(&_sideOverlapFact,          &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(sensorWidth(),              &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(sensorHeight(),             &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(imageWidth(),               &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(imageHeight(),              &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(focalLength(),              &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
    connect(landscape(),                &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);

    _cameraNameChanged();

    setDirty(false);
}

void CameraCalc::setDirty(bool dirty)
{
    if (_dirty != dirty) {
        _dirty = dirty;
        emit dirtyChanged(_dirty);
    }
}

void CameraCalc::_cameraNameChanged(void)
{
    if (_disableRecalc) {
        return;
    }

    QString cameraName = _cameraNameFact.rawValue().toString();

    // Validate known camera name
    bool foundKnownCamera = false;
    CameraMetaData* cameraMetaData = NULL;
    if (!isManualCamera() && !isCustomCamera()) {
        for (int cameraIndex=0; cameraIndex<_knownCameraList.count(); cameraIndex++) {
            cameraMetaData = _knownCameraList[cameraIndex].value<CameraMetaData*>();
            if (cameraName == cameraMetaData->name()) {
                foundKnownCamera = true;
                break;
            }
        }

        if (!foundKnownCamera) {
            // This will cause another camera changed signal which will recurse back to this routine
            _cameraNameFact.setRawValue(customCameraName());
            return;
        }
    }

    _disableRecalc = true;
    if (foundKnownCamera) {
        sensorWidth()->setRawValue          (cameraMetaData->sensorWidth());
        sensorHeight()->setRawValue         (cameraMetaData->sensorHeight());
        imageWidth()->setRawValue           (cameraMetaData->imageWidth());
        imageHeight()->setRawValue          (cameraMetaData->imageHeight());
        focalLength()->setRawValue          (cameraMetaData->focalLength());
        landscape()->setRawValue            (cameraMetaData->landscape());
        fixedOrientation()->setRawValue     (cameraMetaData->fixedOrientation());
        minTriggerInterval()->setRawValue   (cameraMetaData->minTriggerInterval());
    } else {
        if (isManualCamera() || isCustomCamera()) {
            // These values are unknown for these types
            fixedOrientation()->setRawValue(false);
            minTriggerInterval()->setRawValue(0);
            if (isManualCamera()) {
                valueSetIsDistance()->setRawValue(false);
            }
        } else {
            qWarning() << "Internal Error: Not known camera, but now manual or custom either";
        }
    }
    _disableRecalc = false;

    _recalcTriggerDistance();
    _adjustDistanceToSurfaceRelative();
}

void CameraCalc::_recalcTriggerDistance(void)
{
    if (_disableRecalc || isManualCamera()) {
        return;
    }

    _disableRecalc = true;

    double focalLength =    this->focalLength()->rawValue().toDouble();
    double sensorWidth =    this->sensorWidth()->rawValue().toDouble();
    double sensorHeight =   this->sensorHeight()->rawValue().toDouble();
    double imageWidth =     this->imageWidth()->rawValue().toDouble();
    double imageHeight =    this->imageHeight()->rawValue().toDouble();
    double imageDensity =   _imageDensityFact.rawValue().toDouble();

    if (focalLength <= 0 || sensorWidth <= 0 || sensorHeight <= 0 || imageWidth <= 0 || imageHeight <= 0 || imageDensity <= 0) {
        return;
    }

    if (_valueSetIsDistanceFact.rawValue().toBool()) {
        _imageDensityFact.setRawValue((_distanceToSurfaceFact.rawValue().toDouble() * sensorWidth * 100.0) / (imageWidth * focalLength));
    } else {
        _distanceToSurfaceFact.setRawValue((imageWidth * _imageDensityFact.rawValue().toDouble() * focalLength) / (sensorWidth * 100.0));
    }

    imageDensity = _imageDensityFact.rawValue().toDouble();

    if (landscape()->rawValue().toBool()) {
        _imageFootprintSide =       (imageWidth  * imageDensity) / 100.0;
        _imageFootprintFrontal =    (imageHeight * imageDensity) / 100.0;
    } else {
        _imageFootprintSide  =      (imageHeight * imageDensity) / 100.0;
        _imageFootprintFrontal =    (imageWidth  * imageDensity) / 100.0;
    }
    _adjustedFootprintSideFact.setRawValue      (_imageFootprintSide * ((100.0 - _sideOverlapFact.rawValue().toDouble()) / 100.0));
    _adjustedFootprintFrontalFact.setRawValue   (_imageFootprintFrontal * ((100.0 - _frontalOverlapFact.rawValue().toDouble()) / 100.0));

    emit imageFootprintSideChanged      (_imageFootprintSide);
    emit imageFootprintFrontalChanged   (_imageFootprintFrontal);

    _disableRecalc = false;
}

void CameraCalc::save(QJsonObject& json) const
{
    json[JsonHelper::jsonVersionKey] =      1;
    json[adjustedFootprintSideName] =       _adjustedFootprintSideFact.rawValue().toDouble();
    json[adjustedFootprintFrontalName] =    _adjustedFootprintFrontalFact.rawValue().toDouble();
    json[distanceToSurfaceName] =           _distanceToSurfaceFact.rawValue().toDouble();
    json[distanceToSurfaceRelativeName] =   _distanceToSurfaceRelative;
    json[cameraNameName] =                  _cameraNameFact.rawValue().toString();

    if (!isManualCamera()) {
        CameraSpec::save(json);
        json[valueSetIsDistanceName] = _valueSetIsDistanceFact.rawValue().toBool();
        json[imageDensityName] =       _imageDensityFact.rawValue().toDouble();
        json[frontalOverlapName] =     _frontalOverlapFact.rawValue().toDouble();
        json[sideOverlapName] =        _sideOverlapFact.rawValue().toDouble();
    }
}

bool CameraCalc::load(const QJsonObject& json, QString& errorString)
{
    QJsonObject v1Json = json;

    if (!v1Json.contains(JsonHelper::jsonVersionKey)) {
        // Version 0 file. Differences from Version 1 for conversion:
        //  JsonHelper::jsonVersionKey not stored
        //  _jsonCameraSpecTypeKey stores CameraSpecType
        //  _jsonCameraNameKey only set if CameraSpecKnown
        int cameraSpec = v1Json[_jsonCameraSpecTypeKey].toInt(CameraSpecNone);
        if (cameraSpec == CameraSpecCustom) {
            v1Json[cameraNameName] = customCameraName();
        } else if (cameraSpec == CameraSpecNone) {
            v1Json[cameraNameName] = manualCameraName();
        }
        v1Json.remove(_jsonCameraSpecTypeKey);
        v1Json[JsonHelper::jsonVersionKey] = 1;
    }

    int version = v1Json[JsonHelper::jsonVersionKey].toInt();
    if (version != 1) {
        errorString = tr("CameraCalc section version %1 not supported").arg(version);
        return false;
    }

    QList<JsonHelper::KeyValidateInfo> keyInfoList1 = {
        { cameraNameName,                   QJsonValue::String, true },
        { adjustedFootprintSideName,        QJsonValue::Double, true },
        { adjustedFootprintFrontalName,     QJsonValue::Double, true },
        { distanceToSurfaceName,            QJsonValue::Double, true },
        { distanceToSurfaceRelativeName,    QJsonValue::Bool, true },
    };
    if (!JsonHelper::validateKeys(v1Json, keyInfoList1, errorString)) {
        return false;
    }

    _disableRecalc = true;

    _cameraNameFact.setRawValue                 (v1Json[cameraNameName].toString());
    _adjustedFootprintSideFact.setRawValue      (v1Json[adjustedFootprintSideName].toDouble());
    _adjustedFootprintFrontalFact.setRawValue   (v1Json[adjustedFootprintFrontalName].toDouble());
    _distanceToSurfaceFact.setRawValue          (v1Json[distanceToSurfaceName].toDouble());

    _distanceToSurfaceRelative = v1Json[distanceToSurfaceRelativeName].toBool();

    if (!isManualCamera()) {
        QList<JsonHelper::KeyValidateInfo> keyInfoList2 = {
            { valueSetIsDistanceName,   QJsonValue::Bool,   true },
            { imageDensityName,         QJsonValue::Double, true },
            { frontalOverlapName,       QJsonValue::Double, true },
            { sideOverlapName,          QJsonValue::Double, true },
        };
        if (!JsonHelper::validateKeys(v1Json, keyInfoList2, errorString)) {
            _disableRecalc = false;
            return false;
        }

        _valueSetIsDistanceFact.setRawValue (v1Json[valueSetIsDistanceName].toBool());
        _imageDensityFact.setRawValue       (v1Json[imageDensityName].toDouble());
        _frontalOverlapFact.setRawValue     (v1Json[frontalOverlapName].toDouble());
        _sideOverlapFact.setRawValue        (v1Json[sideOverlapName].toDouble());

        if (!CameraSpec::load(v1Json, errorString)) {
            _disableRecalc = false;
            return false;
        }
    }

    _disableRecalc = false;

    return true;
}

QString CameraCalc::customCameraName(void)
{
    return tr("Custom Camera");
}

QString CameraCalc::manualCameraName(void)
{
    return tr("Manual (no camera specs)");
}

void CameraCalc::_adjustDistanceToSurfaceRelative(void)
{
    if (!isManualCamera()) {
        setDistanceToSurfaceRelative(true);
    }
}

void CameraCalc::setDistanceToSurfaceRelative(bool distanceToSurfaceRelative)
{
    if (distanceToSurfaceRelative != _distanceToSurfaceRelative) {
        _distanceToSurfaceRelative = distanceToSurfaceRelative;
        emit distanceToSurfaceRelativeChanged(distanceToSurfaceRelative);
    }
}

void CameraCalc::_setDirty(void)
{
    setDirty(true);
}
<|endoftext|>


<commit_before>#include "otbTestMain.h"
void RegisterTests()
{
  REGISTER_TEST(otbListSampleToHistogramListGeneratorNew);
  REGISTER_TEST(otbStreamingMinMaxImageFilter);
  REGISTER_TEST(otbStreamingMinMaxVectorImageFilterNew);
  REGISTER_TEST(otbVarianceImageFilterNew);
  REGISTER_TEST(otbStreamingStatisticsImageFilterNew);
  REGISTER_TEST(otbListSampleToVariableDimensionHistogramGeneratorNew);
  REGISTER_TEST(otbStreamingHistogramVectorImageFilterNew);
  REGISTER_TEST(otbStreamingStatisticsVectorImageFilterNew);
  REGISTER_TEST(otbRealImageToComplexImageFilterTest);
  REGISTER_TEST(otbHistogramStatisticsFunction);
  REGISTER_TEST(otbGaussianAdditiveNoiseSampleListFilterNew);
  REGISTER_TEST(otbGaussianAdditiveNoiseSampleListFilter);
  REGISTER_TEST(otbNormalizeVectorImageFilterNewTest);
  REGISTER_TEST(otbNormalizeVectorImageFilterTest);
  REGISTER_TEST(otbVectorImageToMatrixNewTest);
  REGISTER_TEST(otbVectorImageToMatrixTest);
  REGISTER_TEST(otbListSampleToVariableDimensionHistogramGenerator);
  REGISTER_TEST(otbStreamingMinMaxImageFilterNew);
  REGISTER_TEST(otbShiftScaleSampleListFilterNew);
  REGISTER_TEST(otbShiftScaleSampleListFilter);
  REGISTER_TEST(otbVectorImageToIntensityImageFilter);
  REGISTER_TEST(otbVarianceImageFilter);
  REGISTER_TEST(otbConcatenateSampleListFilterNew);
  REGISTER_TEST(otbConcatenateSampleListFilter);
  REGISTER_TEST(otbLocalHistogramImageFunctionTest);
  REGISTER_TEST(otbVectorImageToIntensityImageFilterNew);
  REGISTER_TEST(otbProjectiveProjectionNew);
  REGISTER_TEST(otbProjectiveProjectionTestHighSNR);
  REGISTER_TEST(otbShiftScaleVectorImageFilterTest);
  REGISTER_TEST(otbContinuousMinimumMaximumImageCalculatorNew);
  REGISTER_TEST(otbStreamingCompareImageFilterNew);
  REGISTER_TEST(otbStreamingCompareImageFilter);
  REGISTER_TEST(otbStreamingStatisticsMapFromLabelImageFilterTest);
  REGISTER_TEST(otbLocalHistogramImageFunctionNew);
  REGISTER_TEST(otbRealAndImaginaryImageToComplexImageFilterTest);
  REGISTER_TEST(otbStreamingStatisticsImageFilter);
  REGISTER_TEST(otbListSampleToBalancedListSampleFilterNew);
  REGISTER_TEST(otbListSampleToBalancedListSampleFilter);
  REGISTER_TEST(otbStreamingStatisticsVectorImageFilter);
  REGISTER_TEST(otbStreamingMinMaxVectorImageFilter);
  REGISTER_TEST(otbListSampleGeneratorNew);
  REGISTER_TEST(otbListSampleGenerator);
  REGISTER_TEST(otbImaginaryImageToComplexImageFilterTest);
  REGISTER_TEST(otbListSampleToHistogramListGenerator);
  REGISTER_TEST(otbResampleSLCImage);
}
<commit_msg>TEST: Automatic update of test drivers<commit_after>#include "otbTestMain.h"
void RegisterTests()
{
  REGISTER_TEST(otbListSampleToHistogramListGeneratorNew);
  REGISTER_TEST(otbStreamingMinMaxImageFilter);
  REGISTER_TEST(otbStreamingMinMaxVectorImageFilterNew);
  REGISTER_TEST(otbVarianceImageFilterNew);
  REGISTER_TEST(otbStreamingStatisticsImageFilterNew);
  REGISTER_TEST(otbListSampleToVariableDimensionHistogramGeneratorNew);
  REGISTER_TEST(otbStreamingHistogramVectorImageFilterNew);
  REGISTER_TEST(otbStreamingStatisticsVectorImageFilterNew);
  REGISTER_TEST(otbRealImageToComplexImageFilterTest);
  REGISTER_TEST(otbHistogramStatisticsFunction);
  REGISTER_TEST(otbGaussianAdditiveNoiseSampleListFilterNew);
  REGISTER_TEST(otbGaussianAdditiveNoiseSampleListFilter);
  REGISTER_TEST(otbNormalizeVectorImageFilterNewTest);
  REGISTER_TEST(otbNormalizeVectorImageFilterTest);
  REGISTER_TEST(otbVectorImageToMatrixNewTest);
  REGISTER_TEST(otbVectorImageToMatrixTest);
  REGISTER_TEST(otbListSampleToVariableDimensionHistogramGenerator);
  REGISTER_TEST(otbStreamingMinMaxImageFilterNew);
  REGISTER_TEST(otbShiftScaleSampleListFilterNew);
  REGISTER_TEST(otbShiftScaleSampleListFilter);
  REGISTER_TEST(otbVectorImageToIntensityImageFilter);
  REGISTER_TEST(otbVarianceImageFilter);
  REGISTER_TEST(otbConcatenateSampleListFilterNew);
  REGISTER_TEST(otbConcatenateSampleListFilter);
  REGISTER_TEST(otbLocalHistogramImageFunctionTest);
  REGISTER_TEST(otbVectorImageToIntensityImageFilterNew);
  REGISTER_TEST(otbProjectiveProjectionNew);
  REGISTER_TEST(otbProjectiveProjectionTestHighSNR);
  REGISTER_TEST(otbShiftScaleVectorImageFilterTest);
  REGISTER_TEST(otbContinuousMinimumMaximumImageCalculatorNew);
  REGISTER_TEST(otbStreamingCompareImageFilterNew);
  REGISTER_TEST(otbStreamingCompareImageFilter);
  REGISTER_TEST(otbStreamingStatisticsMapFromLabelImageFilterTest);
  REGISTER_TEST(otbLocalHistogramImageFunctionNew);
  REGISTER_TEST(otbRealAndImaginaryImageToComplexImageFilterTest);
  REGISTER_TEST(otbStreamingStatisticsImageFilter);
  REGISTER_TEST(otbListSampleToBalancedListSampleFilterNew);
  REGISTER_TEST(otbListSampleToBalancedListSampleFilter);
  REGISTER_TEST(otbStreamingStatisticsVectorImageFilter);
  REGISTER_TEST(otbStreamingMinMaxVectorImageFilter);
  REGISTER_TEST(otbListSampleGeneratorNew);
  REGISTER_TEST(otbListSampleGenerator);
  REGISTER_TEST(otbImaginaryImageToComplexImageFilterTest);
  REGISTER_TEST(otbListSampleToHistogramListGenerator);
}
<|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 "mitkNavigationDataTransformFilter.h"
#include "mitkNavigationData.h"

#include "mitkTestingMacros.h"

#include <itkQuaternionRigidTransform.h>

#include <itkTransform.h>
#include <itkVector.h>
#include <iostream>

/**Documentation
*  test for the class "NavigationDataTransformFilter".
*/
typedef itk::VersorRigid3DTransform<mitk::ScalarType > TransformType;

typedef itk::Vector<double,3> VectorType;

int mitkNavigationDataTransformFilterTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("NavigationDataTransformFilter")

    // let's create an object of our class
    mitk::NavigationDataTransformFilter::Pointer myFilter = mitk::NavigationDataTransformFilter::New();

  // first test: did this work?
  // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since
  // it makes no sense to continue without an object.
  MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(),"Testing instantiation");

  /* create helper objects: navigation data with position as origin, zero quaternion, zero error and data valid */
  mitk::NavigationData::PositionType initialPos, resultPos;
  mitk::FillVector3D(initialPos, 1.1, 2.2, 3.3);
  mitk::FillVector3D(resultPos, 5.0, 5.0,5.0);

  mitk::NavigationData::OrientationType initialOri(0.0, 0.0, -0.7071, 0.7071);
  mitk::ScalarType initialError(0.0);
  bool initialValid(true);

  mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New();
  nd1->SetPosition(initialPos);
  nd1->SetOrientation(initialOri);
  nd1->SetPositionAccuracy(initialError);
  nd1->SetOrientationAccuracy(initialError);
  nd1->SetDataValid(initialValid);

  MITK_TEST_CONDITION(myFilter->GetPrecompose() == false, "Testing default Precompose mode");

  myFilter->SetPrecompose(true);
  MITK_TEST_CONDITION(myFilter->GetPrecompose() == true, "Testing Set-/GetPrecompose, part 1");

  myFilter->PrecomposeOff();
  MITK_TEST_CONDITION(myFilter->GetPrecompose() == false, "Testing PrecomposeOff");

  myFilter->PrecomposeOn();
  MITK_TEST_CONDITION(myFilter->GetPrecompose() == true, "Testing PrecomposeOn");

  myFilter->SetInput(nd1);
  MITK_TEST_CONDITION(myFilter->GetInput() == nd1, "Testing Set-/GetInput()");

  mitk::NavigationData* output = myFilter->GetOutput();

  /*test case no transform set*/
  MITK_TEST_FOR_EXCEPTION(std::exception, output->Update(););

  /* test transformation */
  mitk::NavigationDataTransformFilter::TransformType::Pointer transform =  mitk::NavigationDataTransformFilter::TransformType::New();
  VectorType translationVector;
  translationVector[0] = 3.9;
  translationVector[1] = 2.8;
  translationVector[2] = 1.7;

  //
  // Test translation-only transform with PrecomposeOff
  //
  transform->Translate(translationVector);

  myFilter->SetRigid3DTransform(transform);
  myFilter->SetPrecompose(false);

  output = myFilter->GetOutput();
  MITK_TEST_CONDITION_REQUIRED(output != NULL, "Testing GetOutput()");

  output->Update(); // execute filter

  MITK_TEST_CONDITION(output->GetPosition() == resultPos, "Testing if translation was calculated correct");
  MITK_TEST_CONDITION( mitk::Equal( output->GetOrientation(),initialOri, 0.00001 ),"Testing if Orientation remains unchanged ");
  MITK_TEST_CONDITION(output->IsDataValid() == initialValid, "Testing if DataValid remains unchanged");

  // Repeat the same translation test with precompose on - results should
  // be the same for a translation-only transform
  myFilter->PrecomposeOn();
  MITK_TEST_CONDITION(output->GetPosition() == resultPos,
                      "Testing if precomposed translation was calculated correct");
  MITK_TEST_CONDITION(mitk::Equal(output->GetOrientation(),initialOri),
                      "Testing if precomposed Orientation remains unchanged ");
  MITK_TEST_CONDITION(output->IsDataValid() == initialValid,
                      "Testing if precomposed DataValid remains unchanged");

  mitk::NavigationDataTransformFilter::Pointer myFilter2 = mitk::NavigationDataTransformFilter::New();
  // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since
  // it makes no sense to continue without an object.
  MITK_TEST_CONDITION_REQUIRED(myFilter2.IsNotNull(),"Testing instantiation");

  // Setup for subsequent PrecomposeOff/PrecomposeOn tests
  mitk::FillVector3D(initialPos, 1.1, 2.2, 3.3);
  initialOri[0] = 0;
  initialOri[1] = 0;
  initialOri[2] = 0;
  initialOri[3] = 1;

  nd1->SetPosition(initialPos);
  nd1->SetOrientation(initialOri);

  myFilter2->SetInput(nd1);

  //
  // Test rotation-only transform with PrecomposeOff
  //
  myFilter2->PrecomposeOff();

  // Rotate 90 degrees about Z axis
  mitk::NavigationDataTransformFilter::TransformType::MatrixType rotMatrix;
  rotMatrix[0][0] = 0;
  rotMatrix[0][1] = 1;
  rotMatrix[0][2] = 0;
  rotMatrix[1][0] = -1;
  rotMatrix[1][1] = 0;
  rotMatrix[1][2] = 0;
  rotMatrix[2][0] = 0;
  rotMatrix[2][1] = 0;
  rotMatrix[2][2] = 1;

  mitk::NavigationDataTransformFilter::TransformType::Pointer transform2 =  mitk::NavigationDataTransformFilter::TransformType::New();
  transform2->SetMatrix(rotMatrix);

  myFilter2->SetRigid3DTransform(transform2);

  mitk::NavigationData* output2 = myFilter2->GetOutput();
  MITK_TEST_CONDITION_REQUIRED(output2 != NULL, "Testing GetOutput()");

  output2->Update(); // execute filter

  mitk::FillVector3D(resultPos,  2.2, -1.1, 3.3);
  mitk::NavigationData::OrientationType resultOri(0.0, 0.0, -0.7071067690849304, 0.7071067690849304);
  MITK_TEST_CONDITION(mitk::Equal(output2->GetPosition(), resultPos, 0.00001), "Testing if position after rotation is correctly calculated");
  MITK_TEST_CONDITION( mitk::Equal(output2->GetOrientation(), resultOri, 0.00001),"Testing if orientation after rotation is correctly caclculated  ");
  MITK_TEST_CONDITION(output2->IsDataValid() == initialValid, "Testing if DataValid remains unchanged");

  //
  // Test rotation-only transform with PrecomposeOn
  //
  myFilter2->PrecomposeOn();
  output2->Update();

  // Output position should be the same as input position for rotation-only with PrecomposeOn
  MITK_TEST_CONDITION(output2->GetPosition() == initialPos,
                      "Testing if precomposed position after rotation is correctly calculated");
  MITK_TEST_CONDITION(mitk::Equal(output2->GetOrientation(), resultOri),
                      "Testing if precomposed orientation after rotation is correctly calculated");
  MITK_TEST_CONDITION(output2->IsDataValid() == initialValid,
                      "Testing if precomposed DataValid remains unchanged");

  //
  // test obscure rotation angle vs. ITK precision requirements
  //
  itk::QuaternionRigidTransform<mitk::NavigationDataTransformFilter::TransformType::ScalarType>::VnlQuaternionType obscureRotationQuat(37,29,71);
  obscureRotationQuat.normalize();                 // Just to demonstrate that even normalizing doesn't help

  itk::QuaternionRigidTransform<mitk::NavigationDataTransformFilter::TransformType::ScalarType>::Pointer rotation =
      itk::QuaternionRigidTransform<mitk::NavigationDataTransformFilter::TransformType::ScalarType>::New();
  rotation->SetRotation(obscureRotationQuat);

  mitk::NavigationDataTransformFilter::TransformType::Pointer transform3 = mitk::NavigationDataTransformFilter::TransformType::New();
  // For lack of an MITK Test macro that tests for *no* exception
  try
  {
    MITK_TEST_OUTPUT_NO_ENDL(<< "Testing whether NavigationDataTransformFilter's internal transform has sufficient precision for ITK ")
    transform3->SetMatrix(rotation->GetMatrix());
    MITK_TEST_OUTPUT(<< " [PASSED]")
    mitk::TestManager::GetInstance()->TestPassed();
  }
  catch(std::exception&)
  {
    MITK_TEST_OUTPUT(<< " [FAILED]")
    mitk::TestManager::GetInstance()->TestFailed();
  }

  //-----------------------------------------------------------------------------------------------------------
  /* now test the filter with multiple inputs */
  mitk::NavigationData::PositionType initialPos2, resultPos2;
  mitk::FillVector3D(initialPos, 1.1, 2.2, 3.3);
  mitk::FillVector3D(initialPos2, -1000.0, 567.89, 0.0);
  mitk::FillVector3D(resultPos, 2.2,-1.1, 3.3);
  mitk::FillVector3D(resultPos2, 567.89, 1000, 0.0);
  mitk::NavigationData::OrientationType initialOri2(0.5,0.5,0.5,0.5);
  mitk::NavigationData::OrientationType resultOri2(0.7071,0.0,0.0,0.7071);
  mitk::NavigationData::Pointer nd2 = mitk::NavigationData::New();

  nd1->SetPosition(initialPos);
  nd1->SetOrientation(initialOri);
  nd1->SetPositionAccuracy(initialError);
  nd1->SetDataValid(initialValid);

  nd2->SetPosition(initialPos2);
  nd2->SetOrientation(initialOri2);
  nd2->SetPositionAccuracy(initialError);
  nd2->SetDataValid(initialValid);

  myFilter = NULL;
  myFilter = mitk::NavigationDataTransformFilter::New();
  myFilter->SetRigid3DTransform(transform2);
  myFilter->SetInput(0, nd1);
  myFilter->SetInput(1, nd2);

  MITK_TEST_CONDITION(((myFilter->GetInput(0) == nd1)
    && (myFilter->GetInput(1) == nd2)), "Testing Set-/GetInput(index, data)");
  output = NULL;
  output2 = NULL;
  output = myFilter->GetOutput();
  output2 = myFilter->GetOutput(1);
  output2->Update(); // execute filter pipeline. this should update both outputs!
  MITK_TEST_CONDITION_REQUIRED(((output != NULL) && (output2 != NULL)), "Testing GetOutput(index)");

  MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(), resultPos, 0.00001), "Testing if position rotation was calculated correct [output 0]");
  MITK_TEST_CONDITION(mitk::Equal(output->GetOrientation(), resultOri, 0.00001),"Testing if orientation rotation was calculated correct [output 0]");
  MITK_TEST_CONDITION(output->IsDataValid() == initialValid, "Testing if DataValid remains unchanged for output 0");

  MITK_TEST_CONDITION(mitk::Equal(output2->GetPosition(), resultPos2, 0.0001), "Testing if rotation was calculated correct [output 1]");
  MITK_TEST_CONDITION(mitk::Equal(output2->GetOrientation(), resultOri2, 0.00001),"Testing if orientation rotation was calculated correct [output 1]");
  MITK_TEST_CONDITION(output2->IsDataValid() == initialValid, "Testing if DataValid remains unchanged for output 1");
  //
  //  /* test if anything changes on second ->Update() */
  output->Update(); // nothing should change, since inputs remain unchanged
  MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(), resultPos, 0.0001) &&
    mitk::Equal(output2->GetPosition(), resultPos2, 0.0001), "Testing translation calculation after second update()");

  /* change an input, see if output changes too */
  mitk::NavigationData::PositionType pos3, resultPos3;
  mitk::FillVector3D(pos3, 123.456, -234.567, 789.987);
  mitk::FillVector3D(resultPos3, -234.567, -123.456, 789.987);
  nd1->SetPosition(pos3);  // nd1 is modified, but nothing should change until pipe gets updated
  MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(),resultPos, 0.00001)
    && mitk::Equal(output2->GetPosition(), resultPos2, 0.0001), "Testing transform calculation after input change, before update()");

  output->Update(); // update pipeline. should recalculate positions, because input has changed
  MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(), resultPos3, 0.00001) &&
    mitk::Equal(output2->GetPosition(), resultPos2, 0.0001), "Testing transform calculation after input change, after update()");

  // always end with this!
  MITK_TEST_END();
}

<commit_msg>fixed merge problem: added epsilon to call of equal method<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 "mitkNavigationDataTransformFilter.h"
#include "mitkNavigationData.h"

#include "mitkTestingMacros.h"

#include <itkQuaternionRigidTransform.h>

#include <itkTransform.h>
#include <itkVector.h>
#include <iostream>

/**Documentation
*  test for the class "NavigationDataTransformFilter".
*/
typedef itk::VersorRigid3DTransform<mitk::ScalarType > TransformType;

typedef itk::Vector<double,3> VectorType;

int mitkNavigationDataTransformFilterTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("NavigationDataTransformFilter")

    // let's create an object of our class
    mitk::NavigationDataTransformFilter::Pointer myFilter = mitk::NavigationDataTransformFilter::New();

  // first test: did this work?
  // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since
  // it makes no sense to continue without an object.
  MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(),"Testing instantiation");

  /* create helper objects: navigation data with position as origin, zero quaternion, zero error and data valid */
  mitk::NavigationData::PositionType initialPos, resultPos;
  mitk::FillVector3D(initialPos, 1.1, 2.2, 3.3);
  mitk::FillVector3D(resultPos, 5.0, 5.0,5.0);

  mitk::NavigationData::OrientationType initialOri(0.0, 0.0, -0.7071, 0.7071);
  mitk::ScalarType initialError(0.0);
  bool initialValid(true);

  mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New();
  nd1->SetPosition(initialPos);
  nd1->SetOrientation(initialOri);
  nd1->SetPositionAccuracy(initialError);
  nd1->SetOrientationAccuracy(initialError);
  nd1->SetDataValid(initialValid);

  MITK_TEST_CONDITION(myFilter->GetPrecompose() == false, "Testing default Precompose mode");

  myFilter->SetPrecompose(true);
  MITK_TEST_CONDITION(myFilter->GetPrecompose() == true, "Testing Set-/GetPrecompose, part 1");

  myFilter->PrecomposeOff();
  MITK_TEST_CONDITION(myFilter->GetPrecompose() == false, "Testing PrecomposeOff");

  myFilter->PrecomposeOn();
  MITK_TEST_CONDITION(myFilter->GetPrecompose() == true, "Testing PrecomposeOn");

  myFilter->SetInput(nd1);
  MITK_TEST_CONDITION(myFilter->GetInput() == nd1, "Testing Set-/GetInput()");

  mitk::NavigationData* output = myFilter->GetOutput();

  /*test case no transform set*/
  MITK_TEST_FOR_EXCEPTION(std::exception, output->Update(););

  /* test transformation */
  mitk::NavigationDataTransformFilter::TransformType::Pointer transform =  mitk::NavigationDataTransformFilter::TransformType::New();
  VectorType translationVector;
  translationVector[0] = 3.9;
  translationVector[1] = 2.8;
  translationVector[2] = 1.7;

  //
  // Test translation-only transform with PrecomposeOff
  //
  transform->Translate(translationVector);

  myFilter->SetRigid3DTransform(transform);
  myFilter->SetPrecompose(false);

  output = myFilter->GetOutput();
  MITK_TEST_CONDITION_REQUIRED(output != NULL, "Testing GetOutput()");

  output->Update(); // execute filter

  MITK_TEST_CONDITION(output->GetPosition() == resultPos, "Testing if translation was calculated correct");
  MITK_TEST_CONDITION( mitk::Equal( output->GetOrientation(),initialOri, 0.00001 ),"Testing if Orientation remains unchanged ");
  MITK_TEST_CONDITION(output->IsDataValid() == initialValid, "Testing if DataValid remains unchanged");

  // Repeat the same translation test with precompose on - results should
  // be the same for a translation-only transform
  myFilter->PrecomposeOn();
  MITK_TEST_CONDITION(output->GetPosition() == resultPos,
                      "Testing if precomposed translation was calculated correct");
  MITK_TEST_CONDITION(mitk::Equal(output->GetOrientation(),initialOri,0.00001),
                      "Testing if precomposed Orientation remains unchanged ");
  MITK_TEST_CONDITION(output->IsDataValid() == initialValid,
                      "Testing if precomposed DataValid remains unchanged");

  mitk::NavigationDataTransformFilter::Pointer myFilter2 = mitk::NavigationDataTransformFilter::New();
  // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since
  // it makes no sense to continue without an object.
  MITK_TEST_CONDITION_REQUIRED(myFilter2.IsNotNull(),"Testing instantiation");

  // Setup for subsequent PrecomposeOff/PrecomposeOn tests
  mitk::FillVector3D(initialPos, 1.1, 2.2, 3.3);
  initialOri[0] = 0;
  initialOri[1] = 0;
  initialOri[2] = 0;
  initialOri[3] = 1;

  nd1->SetPosition(initialPos);
  nd1->SetOrientation(initialOri);

  myFilter2->SetInput(nd1);

  //
  // Test rotation-only transform with PrecomposeOff
  //
  myFilter2->PrecomposeOff();

  // Rotate 90 degrees about Z axis
  mitk::NavigationDataTransformFilter::TransformType::MatrixType rotMatrix;
  rotMatrix[0][0] = 0;
  rotMatrix[0][1] = 1;
  rotMatrix[0][2] = 0;
  rotMatrix[1][0] = -1;
  rotMatrix[1][1] = 0;
  rotMatrix[1][2] = 0;
  rotMatrix[2][0] = 0;
  rotMatrix[2][1] = 0;
  rotMatrix[2][2] = 1;

  mitk::NavigationDataTransformFilter::TransformType::Pointer transform2 =  mitk::NavigationDataTransformFilter::TransformType::New();
  transform2->SetMatrix(rotMatrix);

  myFilter2->SetRigid3DTransform(transform2);

  mitk::NavigationData* output2 = myFilter2->GetOutput();
  MITK_TEST_CONDITION_REQUIRED(output2 != NULL, "Testing GetOutput()");

  output2->Update(); // execute filter

  mitk::FillVector3D(resultPos,  2.2, -1.1, 3.3);
  mitk::NavigationData::OrientationType resultOri(0.0, 0.0, -0.7071067690849304, 0.7071067690849304);
  MITK_TEST_CONDITION(mitk::Equal(output2->GetPosition(), resultPos, 0.00001), "Testing if position after rotation is correctly calculated");
  MITK_TEST_CONDITION(mitk::Equal(output2->GetOrientation(), resultOri, 0.00001),"Testing if orientation after rotation is correctly caclculated  ");
  MITK_TEST_CONDITION(output2->IsDataValid() == initialValid, "Testing if DataValid remains unchanged");

  //
  // Test rotation-only transform with PrecomposeOn
  //
  myFilter2->PrecomposeOn();
  output2->Update();

  // Output position should be the same as input position for rotation-only with PrecomposeOn
  MITK_TEST_CONDITION(output2->GetPosition() == initialPos,
                      "Testing if precomposed position after rotation is correctly calculated");
  MITK_TEST_CONDITION(mitk::Equal(output2->GetOrientation(), resultOri, 0.00001),
                      "Testing if precomposed orientation after rotation is correctly calculated");
  MITK_TEST_CONDITION(output2->IsDataValid() == initialValid,
                      "Testing if precomposed DataValid remains unchanged");

  //
  // test obscure rotation angle vs. ITK precision requirements
  //
  itk::QuaternionRigidTransform<mitk::NavigationDataTransformFilter::TransformType::ScalarType>::VnlQuaternionType obscureRotationQuat(37,29,71);
  obscureRotationQuat.normalize();                 // Just to demonstrate that even normalizing doesn't help

  itk::QuaternionRigidTransform<mitk::NavigationDataTransformFilter::TransformType::ScalarType>::Pointer rotation =
      itk::QuaternionRigidTransform<mitk::NavigationDataTransformFilter::TransformType::ScalarType>::New();
  rotation->SetRotation(obscureRotationQuat);

  mitk::NavigationDataTransformFilter::TransformType::Pointer transform3 = mitk::NavigationDataTransformFilter::TransformType::New();
  // For lack of an MITK Test macro that tests for *no* exception
  try
  {
    MITK_TEST_OUTPUT_NO_ENDL(<< "Testing whether NavigationDataTransformFilter's internal transform has sufficient precision for ITK ")
    transform3->SetMatrix(rotation->GetMatrix());
    MITK_TEST_OUTPUT(<< " [PASSED]")
    mitk::TestManager::GetInstance()->TestPassed();
  }
  catch(std::exception&)
  {
    MITK_TEST_OUTPUT(<< " [FAILED]")
    mitk::TestManager::GetInstance()->TestFailed();
  }

  //-----------------------------------------------------------------------------------------------------------
  /* now test the filter with multiple inputs */
  mitk::NavigationData::PositionType initialPos2, resultPos2;
  mitk::FillVector3D(initialPos, 1.1, 2.2, 3.3);
  mitk::FillVector3D(initialPos2, -1000.0, 567.89, 0.0);
  mitk::FillVector3D(resultPos, 2.2,-1.1, 3.3);
  mitk::FillVector3D(resultPos2, 567.89, 1000, 0.0);
  mitk::NavigationData::OrientationType initialOri2(0.5,0.5,0.5,0.5);
  mitk::NavigationData::OrientationType resultOri2(0.7071,0.0,0.0,0.7071);
  mitk::NavigationData::Pointer nd2 = mitk::NavigationData::New();

  nd1->SetPosition(initialPos);
  nd1->SetOrientation(initialOri);
  nd1->SetPositionAccuracy(initialError);
  nd1->SetDataValid(initialValid);

  nd2->SetPosition(initialPos2);
  nd2->SetOrientation(initialOri2);
  nd2->SetPositionAccuracy(initialError);
  nd2->SetDataValid(initialValid);

  myFilter = NULL;
  myFilter = mitk::NavigationDataTransformFilter::New();
  myFilter->SetRigid3DTransform(transform2);
  myFilter->SetInput(0, nd1);
  myFilter->SetInput(1, nd2);

  MITK_TEST_CONDITION(((myFilter->GetInput(0) == nd1)
    && (myFilter->GetInput(1) == nd2)), "Testing Set-/GetInput(index, data)");
  output = NULL;
  output2 = NULL;
  output = myFilter->GetOutput();
  output2 = myFilter->GetOutput(1);
  output2->Update(); // execute filter pipeline. this should update both outputs!
  MITK_TEST_CONDITION_REQUIRED(((output != NULL) && (output2 != NULL)), "Testing GetOutput(index)");

  MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(), resultPos, 0.00001), "Testing if position rotation was calculated correct [output 0]");
  MITK_TEST_CONDITION(mitk::Equal(output->GetOrientation(), resultOri, 0.00001),"Testing if orientation rotation was calculated correct [output 0]");
  MITK_TEST_CONDITION(output->IsDataValid() == initialValid, "Testing if DataValid remains unchanged for output 0");

  MITK_TEST_CONDITION(mitk::Equal(output2->GetPosition(), resultPos2, 0.0001), "Testing if rotation was calculated correct [output 1]");
  MITK_TEST_CONDITION(mitk::Equal(output2->GetOrientation(), resultOri2, 0.00001),"Testing if orientation rotation was calculated correct [output 1]");
  MITK_TEST_CONDITION(output2->IsDataValid() == initialValid, "Testing if DataValid remains unchanged for output 1");
  //
  //  /* test if anything changes on second ->Update() */
  output->Update(); // nothing should change, since inputs remain unchanged
  MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(), resultPos, 0.0001) &&
    mitk::Equal(output2->GetPosition(), resultPos2, 0.0001), "Testing translation calculation after second update()");

  /* change an input, see if output changes too */
  mitk::NavigationData::PositionType pos3, resultPos3;
  mitk::FillVector3D(pos3, 123.456, -234.567, 789.987);
  mitk::FillVector3D(resultPos3, -234.567, -123.456, 789.987);
  nd1->SetPosition(pos3);  // nd1 is modified, but nothing should change until pipe gets updated
  MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(),resultPos, 0.00001)
    && mitk::Equal(output2->GetPosition(), resultPos2, 0.0001), "Testing transform calculation after input change, before update()");

  output->Update(); // update pipeline. should recalculate positions, because input has changed
  MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(), resultPos3, 0.00001) &&
    mitk::Equal(output2->GetPosition(), resultPos2, 0.0001), "Testing transform calculation after input change, after update()");

  // always end with this!
  MITK_TEST_END();
}

<|endoftext|>


<commit_before><commit_msg>[TD]fix regression in multi source selection<commit_after><|endoftext|>


<commit_before><commit_msg>code simplification<commit_after><|endoftext|>


<commit_before>// ----------------------------------------------------------------------------
// PSP Player Emulation Suite
// Copyright (C) 2006 Ben Vanik (noxa)
// Licensed under the LGPL - see License.txt in the project root for details
// ----------------------------------------------------------------------------

#include "StdAfx.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#pragma unmanaged
#include "MemoryPool.h"
#pragma managed
#include "OglDriver.h"
#include "VideoApi.h"
#include <string>

using namespace System::Diagnostics;
using namespace System::Threading;
using namespace Noxa::Emulation::Psp;
using namespace Noxa::Emulation::Psp::Video;
using namespace Noxa::Emulation::Psp::Video::Native;

// This interface works by adding lists to a linked list of waiting lists.
// When Sync is called, the pending lists are set to _pendingBatch and the
// _lists/etc are reset to wait for more lists. When the video worker calls
// GetNextListBatch() it will grab _pendingBatch if possible. If there is
// already a batch in _pendingBatch when Sync is called, the existing
// _pendingBatch is cleared - effectively implementing frame skipping (for
// the case when the video worker cannot grab batches fast enough).
// If frameskipping is not desired, if Sync is called and _pendingBatch has
// data it should wait until GetNextListBatch() is called.

// After this many lists have been allocated, break - it means we probably have an issue
#define LISTCOUNTALERTTHRESHOLD 100

#ifdef _DEBUG
#define BREAK __break()
#else
#define BREAK
#endif

CRITICAL_SECTION _cs;
HANDLE _hSyncEvent;
#define LOCK EnterCriticalSection( &_cs )
#define UNLOCK LeaveCriticalSection( &_cs )

VdlRef* _lists;
VdlRef* _listsTail;
int _nextListId;
int _listCount;

VdlRef* _pendingBatch;
int _pendingCount;

MemoryPool* _pool;

// Statistics
extern uint _processedFrames;
extern uint _skippedFrames;
extern uint _vcount;

void __break()
{
	Debugger::Break();
}

VdlRef* GetNextListBatch();
void MigrateBatch( bool waitIfPending );
void FreeList( VideoDisplayList* list );

#pragma unmanaged

VdlRef* GetNextListBatch()
{
	LOCK;

	MigrateBatch( false );

	VdlRef* batch = _pendingBatch;
	_pendingBatch = NULL;
	_pendingCount = 0;

#ifdef STATISTICS
	if( batch != NULL )
		_processedFrames++;
#endif

	UNLOCK;

	PulseEvent( _hSyncEvent );

	return batch;
}

void FreeList( VideoDisplayList* list )
{
	// Should we be locked here?

	_pool->Release( list->Packets );
#ifdef _DEBUG
	memset( list, 0, sizeof( VideoDisplayList ) );
#endif
	SAFEFREE( list );
}

// Caller needs to lock!
void MigrateBatch( bool waitIfPending )
{
	VdlRef* batch = NULL;
	VdlRef* batchTail = NULL;
	int fetched = 0;

	VdlRef* ref;

	// Remove old batch if needed or wait on it
	if( _pendingBatch != NULL )
	{
		if( waitIfPending == true )
			WaitForSingleObject( _hSyncEvent, INFINITE );
		else
		{
			// Clear old list
			ref = _pendingBatch;
			while( ref != NULL )
			{
				VdlRef* next = ref->Next;

				FreeList( ref->List );
				SAFEFREE( ref );

				ref = next;
			}
			_pendingBatch = NULL;

#ifdef STATISTICS
			_skippedFrames++;
#endif
		}
	}

	_pendingCount = 0;

	ref = _lists;
	VdlRef* prev = NULL;
	while( ref != NULL )
	{
		if( ref->List->Ready == true )
		{
			VdlRef* next = ref->Next;
			if( prev != NULL )
				prev->Next = next;
			ref->Next = NULL;

			if( batch == NULL )
				batch = ref;
			if( batchTail != NULL )
				batchTail->Next = ref;
			batchTail = ref;

			if( ref == _lists )
				_lists = next;
			if( ref == _listsTail )
			{
				if( next == NULL )
					_listsTail = prev;
				else
					_listsTail = next;
			}

			fetched++;

			// prev stays what it is as it is the previous still in the list
			ref = next;
		}
		else
		{
			prev = ref;
			ref = ref->Next;
		}
	}

	_listCount -= fetched;
	_pendingCount = fetched;

	_pendingBatch = batch;
}

void niSetup( MemoryPool* pool )
{
	_pool = pool;
	_lists = NULL;
	_listsTail = NULL;
	_nextListId = 1;
	_listCount = 0;

	_pendingBatch = NULL;
	_pendingCount = 0;
}

void FreeLL( VdlRef* head )
{
	VdlRef* ref = head;
	while( ref != NULL )
	{
		VdlRef* next = ref->Next;

		FreeList( ref->List );
		SAFEFREE( ref );

		ref = next;
	}
}

void niCleanup()
{
	LOCK;

	FreeLL( _pendingBatch );
	_pendingBatch = NULL;

	_listsTail = NULL;
	FreeLL( _lists );
	_lists = NULL;

	_nextListId = 1;
	_listCount = 0;
	_pendingCount = 0;

	_pool = NULL;

	UNLOCK;
}

uint niGetVcount()
{
	return _vcount;
}

void niSwitchFrameBuffer( int address, int bufferWidth, int pixelFormat, int syncMode )
{
	// TODO: switch frame buffer
}

VideoDisplayList* niFindList( int listId )
{
	LOCK;

	VdlRef* ref = _lists;
	if( ref == NULL )
	{
		UNLOCK;
		return NULL;
	}

	// Check tail first - we often get called when updating the last list
	if( _listsTail != NULL )
	{
		if( _listsTail->List->ID == listId )
		{
			VideoDisplayList* vdl = _listsTail->List;
			UNLOCK;
			return vdl;
		}
	}

	while( ref != NULL )
	{
		if( ref->List->ID == listId )
		{
			VideoDisplayList* vdl = ref->List;
			UNLOCK;
			return vdl;
		}
		ref = ref->Next;
	}

	UNLOCK;
	return NULL;
}

int niEnqueueList( VideoDisplayList* list, bool immediate )
{
	int listId = _nextListId++;
	list->ID = listId;

	VdlRef* ref = ( VdlRef* )malloc( sizeof( VdlRef ) );
	ref->List = list;

	LOCK;

	if( immediate == true )
	{
		// Insert at head
		ref->Next = _lists;
		_lists = ref;
		if( _listsTail == NULL )
			_listsTail = ref;
	}
	else
	{
		// Append
		ref->Next = NULL;
		if( _listsTail != NULL )
			_listsTail->Next = ref;
		_listsTail = ref;
		if( _lists == NULL )
			_lists = ref;
	}

	_listCount++;

	UNLOCK;

#ifdef _DEBUG
	if( _listCount > LISTCOUNTALERTTHRESHOLD )
		BREAK;
#endif

	return listId;
}

void niDequeueList( int listId )
{
	LOCK;

	VdlRef* ref = _lists;
	if( ref == NULL )
	{
		UNLOCK;
		return;
	}

	VdlRef* prev = NULL;
	while( ref != NULL )
	{
		if( ref->List->ID == listId )
		{
			VdlRef* next = ref->Next;
			if( prev != NULL )
				prev->Next = next;

			if( ref == _lists )
				_lists = next;
			if( ref == _listsTail )
				_listsTail = prev;

			FreeList( ref->List );
			SAFEFREE( ref );

			_listCount--;

			UNLOCK;
			return;
		}
		prev = ref;
		ref = ref->Next;
	}

	UNLOCK;
}

void niSyncList( int listId )
{
}

void niSync()
{
	LOCK;

#ifdef FRAMESKIPPING
	MigrateBatch( false );
#else
	MigrateBatch( true );
#endif

	UNLOCK;
}

void niWaitForVsync()
{
	// Wait for 1/60th of a second - we do it a little less than 16ms cause
	// we do take time to render - ideally we wouldn't call Sleep cause it causes
	// a context switch and has poor accuracy
	Sleep( 16 );
	//WaitForSingleObject( _hSyncEvent, 60 / 1000 );
}

#pragma managed

void OglDriver::SetupNativeInterface()
{
	VideoApi* ni = ( VideoApi* )_nativeInterface;

	ni->Setup = &niSetup;
	ni->Cleanup = &niCleanup;
	ni->GetVcount = &niGetVcount;
	ni->SwitchFrameBuffer = &niSwitchFrameBuffer;
	ni->FindList = &niFindList;
	ni->EnqueueList = &niEnqueueList;
	ni->DequeueList = &niDequeueList;
	ni->SyncList = &niSyncList;
	ni->Sync = &niSync;
	ni->WaitForVsync = &niWaitForVsync;

	InitializeCriticalSection( &_cs );

	_hSyncEvent = CreateEvent( NULL, false, false, NULL );
}

void OglDriver::DestroyNativeInterface()
{
	CloseHandle( _hSyncEvent );
	_hSyncEvent = NULL;

	DeleteCriticalSection( &_cs );
}
<commit_msg>Fix for vsync wait so it does it right. PSPTris now attempts around 59.7FPS (instead of 300 like before), meaning that it is damn close.<commit_after>// ----------------------------------------------------------------------------
// PSP Player Emulation Suite
// Copyright (C) 2006 Ben Vanik (noxa)
// Licensed under the LGPL - see License.txt in the project root for details
// ----------------------------------------------------------------------------

#include "StdAfx.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#pragma unmanaged
#include "MemoryPool.h"
#pragma managed
#include "OglDriver.h"
#include "VideoApi.h"
#include <string>

using namespace System::Diagnostics;
using namespace System::Threading;
using namespace Noxa::Emulation::Psp;
using namespace Noxa::Emulation::Psp::Video;
using namespace Noxa::Emulation::Psp::Video::Native;

// This interface works by adding lists to a linked list of waiting lists.
// When Sync is called, the pending lists are set to _pendingBatch and the
// _lists/etc are reset to wait for more lists. When the video worker calls
// GetNextListBatch() it will grab _pendingBatch if possible. If there is
// already a batch in _pendingBatch when Sync is called, the existing
// _pendingBatch is cleared - effectively implementing frame skipping (for
// the case when the video worker cannot grab batches fast enough).
// If frameskipping is not desired, if Sync is called and _pendingBatch has
// data it should wait until GetNextListBatch() is called.

// After this many lists have been allocated, break - it means we probably have an issue
#define LISTCOUNTALERTTHRESHOLD 100

#ifdef _DEBUG
#define BREAK __break()
#else
#define BREAK
#endif

CRITICAL_SECTION _cs;
HANDLE _hSyncEvent;
#define LOCK EnterCriticalSection( &_cs )
#define UNLOCK LeaveCriticalSection( &_cs )

VdlRef* _lists;
VdlRef* _listsTail;
int _nextListId;
int _listCount;

VdlRef* _pendingBatch;
int _pendingCount;

MemoryPool* _pool;

int64 _lastVsync;

// Statistics
extern uint _processedFrames;
extern uint _skippedFrames;
extern uint _vcount;

void __break()
{
	Debugger::Break();
}

VdlRef* GetNextListBatch();
void MigrateBatch( bool waitIfPending );
void FreeList( VideoDisplayList* list );

#pragma unmanaged

VdlRef* GetNextListBatch()
{
	LOCK;

	MigrateBatch( false );

	VdlRef* batch = _pendingBatch;
	_pendingBatch = NULL;
	_pendingCount = 0;

#ifdef STATISTICS
	if( batch != NULL )
		_processedFrames++;
#endif

	UNLOCK;

	PulseEvent( _hSyncEvent );

	return batch;
}

void FreeList( VideoDisplayList* list )
{
	// Should we be locked here?

	_pool->Release( list->Packets );
#ifdef _DEBUG
	memset( list, 0, sizeof( VideoDisplayList ) );
#endif
	SAFEFREE( list );
}

// Caller needs to lock!
void MigrateBatch( bool waitIfPending )
{
	VdlRef* batch = NULL;
	VdlRef* batchTail = NULL;
	int fetched = 0;

	VdlRef* ref;

	// Remove old batch if needed or wait on it
	if( _pendingBatch != NULL )
	{
		if( waitIfPending == true )
			WaitForSingleObject( _hSyncEvent, INFINITE );
		else
		{
			// Clear old list
			ref = _pendingBatch;
			while( ref != NULL )
			{
				VdlRef* next = ref->Next;

				FreeList( ref->List );
				SAFEFREE( ref );

				ref = next;
			}
			_pendingBatch = NULL;

#ifdef STATISTICS
			_skippedFrames++;
#endif
		}
	}

	_pendingCount = 0;

	ref = _lists;
	VdlRef* prev = NULL;
	while( ref != NULL )
	{
		if( ref->List->Ready == true )
		{
			VdlRef* next = ref->Next;
			if( prev != NULL )
				prev->Next = next;
			ref->Next = NULL;

			if( batch == NULL )
				batch = ref;
			if( batchTail != NULL )
				batchTail->Next = ref;
			batchTail = ref;

			if( ref == _lists )
				_lists = next;
			if( ref == _listsTail )
			{
				if( next == NULL )
					_listsTail = prev;
				else
					_listsTail = next;
			}

			fetched++;

			// prev stays what it is as it is the previous still in the list
			ref = next;
		}
		else
		{
			prev = ref;
			ref = ref->Next;
		}
	}

	_listCount -= fetched;
	_pendingCount = fetched;

	_pendingBatch = batch;
}

void niSetup( MemoryPool* pool )
{
	_pool = pool;
	_lists = NULL;
	_listsTail = NULL;
	_nextListId = 1;
	_listCount = 0;

	_pendingBatch = NULL;
	_pendingCount = 0;
}

void FreeLL( VdlRef* head )
{
	VdlRef* ref = head;
	while( ref != NULL )
	{
		VdlRef* next = ref->Next;

		FreeList( ref->List );
		SAFEFREE( ref );

		ref = next;
	}
}

void niCleanup()
{
	LOCK;

	FreeLL( _pendingBatch );
	_pendingBatch = NULL;

	_listsTail = NULL;
	FreeLL( _lists );
	_lists = NULL;

	_nextListId = 1;
	_listCount = 0;
	_pendingCount = 0;

	_pool = NULL;

	UNLOCK;
}

uint niGetVcount()
{
	return _vcount;
}

void niSwitchFrameBuffer( int address, int bufferWidth, int pixelFormat, int syncMode )
{
	// TODO: switch frame buffer
}

VideoDisplayList* niFindList( int listId )
{
	LOCK;

	VdlRef* ref = _lists;
	if( ref == NULL )
	{
		UNLOCK;
		return NULL;
	}

	// Check tail first - we often get called when updating the last list
	if( _listsTail != NULL )
	{
		if( _listsTail->List->ID == listId )
		{
			VideoDisplayList* vdl = _listsTail->List;
			UNLOCK;
			return vdl;
		}
	}

	while( ref != NULL )
	{
		if( ref->List->ID == listId )
		{
			VideoDisplayList* vdl = ref->List;
			UNLOCK;
			return vdl;
		}
		ref = ref->Next;
	}

	UNLOCK;
	return NULL;
}

int niEnqueueList( VideoDisplayList* list, bool immediate )
{
	int listId = _nextListId++;
	list->ID = listId;

	VdlRef* ref = ( VdlRef* )malloc( sizeof( VdlRef ) );
	ref->List = list;

	LOCK;

	if( immediate == true )
	{
		// Insert at head
		ref->Next = _lists;
		_lists = ref;
		if( _listsTail == NULL )
			_listsTail = ref;
	}
	else
	{
		// Append
		ref->Next = NULL;
		if( _listsTail != NULL )
			_listsTail->Next = ref;
		_listsTail = ref;
		if( _lists == NULL )
			_lists = ref;
	}

	_listCount++;

	UNLOCK;

#ifdef _DEBUG
	if( _listCount > LISTCOUNTALERTTHRESHOLD )
		BREAK;
#endif

	return listId;
}

void niDequeueList( int listId )
{
	LOCK;

	VdlRef* ref = _lists;
	if( ref == NULL )
	{
		UNLOCK;
		return;
	}

	VdlRef* prev = NULL;
	while( ref != NULL )
	{
		if( ref->List->ID == listId )
		{
			VdlRef* next = ref->Next;
			if( prev != NULL )
				prev->Next = next;

			if( ref == _lists )
				_lists = next;
			if( ref == _listsTail )
				_listsTail = prev;

			FreeList( ref->List );
			SAFEFREE( ref );

			_listCount--;

			UNLOCK;
			return;
		}
		prev = ref;
		ref = ref->Next;
	}

	UNLOCK;
}

void niSyncList( int listId )
{
}

void niSync()
{
	LOCK;

#ifdef FRAMESKIPPING
	MigrateBatch( false );
#else
	MigrateBatch( true );
#endif

	UNLOCK;
}

void niWaitForVsync()
{
	int64 tick;
	GetSystemTimeAsFileTime( ( FILETIME* )&tick );
	int64 duration = ( tick - _lastVsync );
	_lastVsync = tick;

	// ticks are 100ns, we need ms
	duration /= 1000000;

	// If we are under 16ms, wait until 16ms
	if( duration < 16 )
		Sleep( 16 - ( int )duration );

	// Wait for 1/60th of a second - we do it a little less than 16ms cause
	// we do take time to render - ideally we wouldn't call Sleep cause it causes
	// a context switch and has poor accuracy
	//Sleep( 16 );
	//WaitForSingleObject( _hSyncEvent, 60 / 1000 );
}

#pragma managed

void OglDriver::SetupNativeInterface()
{
	VideoApi* ni = ( VideoApi* )_nativeInterface;

	ni->Setup = &niSetup;
	ni->Cleanup = &niCleanup;
	ni->GetVcount = &niGetVcount;
	ni->SwitchFrameBuffer = &niSwitchFrameBuffer;
	ni->FindList = &niFindList;
	ni->EnqueueList = &niEnqueueList;
	ni->DequeueList = &niDequeueList;
	ni->SyncList = &niSyncList;
	ni->Sync = &niSync;
	ni->WaitForVsync = &niWaitForVsync;

	InitializeCriticalSection( &_cs );

	_hSyncEvent = CreateEvent( NULL, false, false, NULL );

	_lastVsync = 0;
}

void OglDriver::DestroyNativeInterface()
{
	CloseHandle( _hSyncEvent );
	_hSyncEvent = NULL;

	DeleteCriticalSection( &_cs );
}
<|endoftext|>


<commit_before>/*
 * =====================================================================================
 *
 *       Filename:  kmer_query.cc
 *
 *    Description:
 *
 *        Version:  1.0
 *        Created:  04/27/2016 08:48:26 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Prashant Pandey (ppandey@cs.stonybrook.edu)
 *                  Rob Patro (rob.patro@cs.stonybrook.edu)
 *                  Rob Johnson (rob@cs.stonybrook.edu)
 *   Organization:  Stony Brook University
 *
 * =====================================================================================
 */

#include <iostream>
#include <cstring>
#include <vector>
#include <set>
#include <bitset>
#include <cassert>
#include <fstream>

#include <time.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>

#include "clipp.h"
#include "threadsafe-gqf/gqf.h"

using namespace std;

/* Print elapsed time using the start and end timeval */
void print_time_elapsed(string desc, struct timeval* start, struct timeval* end)
{
	struct timeval elapsed;
	if (start->tv_usec > end->tv_usec) {
		end->tv_usec += 1000000;
		end->tv_sec--;
	}
	elapsed.tv_usec = end->tv_usec - start->tv_usec;
	elapsed.tv_sec = end->tv_sec - start->tv_sec;
	float time_elapsed = (elapsed.tv_sec * 1000000 + elapsed.tv_usec)/1000000.f;
	cout << desc << "Total Time Elapsed: " << to_string(time_elapsed) << " seconds" << endl;
}

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  main
 *  Description:
 * =====================================================================================
 */
int main ( int argc, char *argv[] )
{
	QF cfa, cfb;

	//if (argc == 2) {
		//string arg_help(argv[1]);
		//if (arg_help.compare("-h") != 0 || arg_help.compare("-help") != 0) {
			//cout << "./squeakr-inner-product [OPTIONS]" << endl
					 //<< "file1: dataset 1 Squeakr representation" << endl
					 //<< "file2: dataset 2 Squeakr representation" << endl;
			//exit(0);
		//}
	//}

	string ds_filea;
	string ds_fileb;
	uint64_t inner_prod;
	struct timeval start, end;
	struct timezone tzp;

	using namespace clipp;
	auto cli = (
							required("-a", "--cqf-file-first") & value("cqf-file-first", ds_filea) % "first input CQF file",
							required("-b", "--cqf-file-second") & value("cqf-file-second", ds_filea) % "second input CQF file",
							option("-h", "--help")  % "show help"
						 );

	auto res = parse(argc, argv, cli);

	if (!res) {
		std::cout << make_man_page(cli, argv[0]) << "\n";
		return 1;
	}

	srand(time(NULL));

	//Initialize the QF
	cout << "Mmap the QF from disk" << endl;
	qf_read(&cfa, ds_filea.c_str());
	qf_read(&cfb, ds_fileb.c_str());

	if (cfa.metadata->seed != cfb.metadata->seed) {
		cerr << "Input CQFs do not have the same seed." << std::endl;
		return 1;
	}

	cout << "Performing inner product querries." << endl;

	gettimeofday(&start, &tzp);
	inner_prod = qf_inner_product(&cfa, &cfb);
	gettimeofday(&end, &tzp);
	cout << "Inner product: " << inner_prod << "\n" << endl;
	print_time_elapsed("", &start, &end);

	return EXIT_SUCCESS;
}				/* ----------  end of function main  ---------- */

<commit_msg>Fixing a minor bug in inner product CLI.<commit_after>/*
 * =====================================================================================
 *
 *       Filename:  kmer_query.cc
 *
 *    Description:
 *
 *        Version:  1.0
 *        Created:  04/27/2016 08:48:26 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Prashant Pandey (ppandey@cs.stonybrook.edu)
 *                  Rob Patro (rob.patro@cs.stonybrook.edu)
 *                  Rob Johnson (rob@cs.stonybrook.edu)
 *   Organization:  Stony Brook University
 *
 * =====================================================================================
 */

#include <iostream>
#include <cstring>
#include <vector>
#include <set>
#include <bitset>
#include <cassert>
#include <fstream>

#include <time.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>

#include "clipp.h"
#include "threadsafe-gqf/gqf.h"

using namespace std;

/* Print elapsed time using the start and end timeval */
void print_time_elapsed(string desc, struct timeval* start, struct timeval* end)
{
	struct timeval elapsed;
	if (start->tv_usec > end->tv_usec) {
		end->tv_usec += 1000000;
		end->tv_sec--;
	}
	elapsed.tv_usec = end->tv_usec - start->tv_usec;
	elapsed.tv_sec = end->tv_sec - start->tv_sec;
	float time_elapsed = (elapsed.tv_sec * 1000000 + elapsed.tv_usec)/1000000.f;
	cout << desc << "Total Time Elapsed: " << to_string(time_elapsed) << " seconds" << endl;
}

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  main
 *  Description:
 * =====================================================================================
 */
int main ( int argc, char *argv[] )
{
	QF cfa, cfb;

	//if (argc == 2) {
		//string arg_help(argv[1]);
		//if (arg_help.compare("-h") != 0 || arg_help.compare("-help") != 0) {
			//cout << "./squeakr-inner-product [OPTIONS]" << endl
					 //<< "file1: dataset 1 Squeakr representation" << endl
					 //<< "file2: dataset 2 Squeakr representation" << endl;
			//exit(0);
		//}
	//}

	string ds_filea;
	string ds_fileb;
	uint64_t inner_prod;
	struct timeval start, end;
	struct timezone tzp;

	using namespace clipp;
	auto cli = (
							required("-a", "--cqf-file-first") & value("cqf-file-first", ds_filea) % "first input CQF file",
							required("-b", "--cqf-file-second") & value("cqf-file-second", ds_fileb) % "second input CQF file",
							option("-h", "--help")  % "show help"
						 );

	auto res = parse(argc, argv, cli);

	if (!res) {
		std::cout << make_man_page(cli, argv[0]) << "\n";
		return 1;
	}

	srand(time(NULL));

	//Initialize the QF
	cout << "Mmap the QF from disk" << endl;
	qf_read(&cfa, ds_filea.c_str());
	qf_read(&cfb, ds_fileb.c_str());

	if (cfa.metadata->seed != cfb.metadata->seed) {
		cerr << "Input CQFs do not have the same seed." << std::endl;
		return 1;
	}

	cout << "Performing inner product querries." << endl;

	gettimeofday(&start, &tzp);
	inner_prod = qf_inner_product(&cfa, &cfb);
	gettimeofday(&end, &tzp);
	cout << "Inner product: " << inner_prod << "\n" << endl;
	print_time_elapsed("", &start, &end);

	return EXIT_SUCCESS;
}				/* ----------  end of function main  ---------- */

<|endoftext|>


<commit_before>#include "PreIntegrateEnvBRDF.h"
#include "ShaderManager.h"
#include "ComputeShader.h"
#include "DirectX.h"
#include "ShaderFactory.hpp"

using namespace Math;
using namespace Device;
using namespace Core;
using namespace Rendering;
using namespace Rendering::Precompute;
using namespace Rendering::Shader;
using namespace Rendering::Manager;
using namespace Rendering::Texture;
using namespace Rendering::Manager;
using namespace Rendering::Factory;

Texture::Texture2D& PreIntegrateEnvBRDF::CreatePreBRDFMap(Device::DirectX& dx, ShaderManager& shaderMgr)
{
	std::shared_ptr<ComputeShader> shader = ShaderFactory::LoadComputeShader(dx, shaderMgr, "PreIntegrateEnvBRDF", "CS", nullptr, nullptr);

	const Size<uint> size(256, 256);

	_texture.Initialize(dx, size.w, size.h,
						DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT,
						D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS, 1, 1);

	shader->Dispatch(dx, ComputeShader::ThreadGroup((size.w + PRE_INTEGRATE_TILE_RES - 1) / PRE_INTEGRATE_TILE_RES,
													(size.h + PRE_INTEGRATE_TILE_RES - 1) / PRE_INTEGRATE_TILE_RES, 1));
	shaderMgr.GetPool<ComputeShader>().Delete(shader->GetKey());

	return _texture;
}<commit_msg>PreInegrateEnvBRDF - output UAV 설정함<commit_after>#include "PreIntegrateEnvBRDF.h"
#include "ShaderManager.h"
#include "ComputeShader.h"
#include "DirectX.h"
#include "ShaderFactory.hpp"
#include "AutoBinder.hpp"

using namespace Math;
using namespace Device;
using namespace Core;
using namespace Rendering;
using namespace Rendering::Precompute;
using namespace Rendering::Shader;
using namespace Rendering::Manager;
using namespace Rendering::Texture;
using namespace Rendering::Manager;
using namespace Rendering::Factory;

Texture::Texture2D& PreIntegrateEnvBRDF::CreatePreBRDFMap(Device::DirectX& dx, ShaderManager& shaderMgr)
{
	std::shared_ptr<ComputeShader> shader = ShaderFactory::LoadComputeShader(dx, shaderMgr, "PreIntegrateEnvBRDF", "CS", nullptr, "@PreIntegrateEnvBRDF");

	const Size<uint> size(256, 256);

	_texture.Initialize(dx, size.w, size.h,
						DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16_FLOAT,
						D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS, 1, 1);

	AutoBinderUAV output(dx, UAVBindIndex(0), _texture.GetUnorderedAccessView());
	shader->Dispatch(dx, ComputeShader::ThreadGroup((size.w + PRE_INTEGRATE_TILE_RES - 1) / PRE_INTEGRATE_TILE_RES,
													(size.h + PRE_INTEGRATE_TILE_RES - 1) / PRE_INTEGRATE_TILE_RES, 1));
	shaderMgr.GetPool<ComputeShader>().Delete(shader->GetKey());

	return _texture;
}<|endoftext|>


<commit_before>/*
    open source routing machine
    Copyright (C) Dennis Luxen, others 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.

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 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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "DataStructures/SharedMemoryFactory.h"
#include "DataStructures/SharedMemoryVectorWrapper.h"
#include "Util/SimpleLogger.h"
#include "typedefs.h"

int main(int argc, char * argv[]) {
    try {
        LogPolicy::GetInstance().Unmute();

    } catch(const std::exception & e) {
        SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();

    }

    return 0;
}
<commit_msg>implementing loading of data into shared memory<commit_after>/*
    open source routing machine
    Copyright (C) Dennis Luxen, others 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.

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 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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "DataStructures/QueryEdge.h"
#include "DataStructures/SharedMemoryFactory.h"
#include "DataStructures/SharedMemoryVectorWrapper.h"
#include "DataStructures/StaticGraph.h"
#include "Server/DataStructures/SharedDataType.h"
#include "Util/BoostFilesystemFix.h"
#include "Util/GraphLoader.h"
#include "Util/IniFile.h"
#include "Util/SimpleLogger.h"
#include "typedefs.h"

#include <boost/integer.hpp>
#include <boost/filesystem/fstream.hpp>

#include <string>
#include <vector>

typedef StaticGraph<QueryEdge::EdgeData> QueryGraph;

void StoreIntegerInSharedMemory(
    const uint64_t value,
    const SharedDataType data_type)
{
        SharedMemory * memory = SharedMemoryFactory::Get(
            data_type,
            sizeof(uint64_t)
        );
        uint64_t * ptr = static_cast<uint64_t *>( memory->Ptr() );
        *ptr = value;
}

int main(int argc, char * argv[]) {
    try {
        LogPolicy::GetInstance().Unmute();
        SimpleLogger().Write() << "Checking input parameters";

        boost::filesystem::path base_path = boost::filesystem::absolute(
            (argc > 1 ? argv[1] : "server.ini")
        ).parent_path();
        IniFile server_config((argc > 1 ? argv[1] : "server.ini"));
        //check contents of config file
        if ( !server_config.Holds("hsgrData")) {
            throw OSRMException("no ram index file name in server ini");
        }
        if ( !server_config.Holds("ramIndex") ) {
            throw OSRMException("no mem index file name in server ini");
        }
        if ( !server_config.Holds("nodesData") ) {
            throw OSRMException("no nodes file name in server ini");
        }
        if ( !server_config.Holds("edgesData") ) {
            throw OSRMException("no edges file name in server ini");
        }

        //generate paths of data files
        boost::filesystem::path hsgr_path = boost::filesystem::absolute(
                server_config.GetParameter("hsgrData"),
                base_path
        );
        boost::filesystem::path ram_index_path = boost::filesystem::absolute(
                server_config.GetParameter("ramIndex"),
                base_path
        );
        boost::filesystem::path node_data_path = boost::filesystem::absolute(
                server_config.GetParameter("nodesData"),
                base_path
        );
        boost::filesystem::path edge_data_path = boost::filesystem::absolute(
                server_config.GetParameter("edgesData"),
                base_path
        );
        boost::filesystem::path name_data_path = boost::filesystem::absolute(
                server_config.GetParameter("namesData"),
                base_path
        );
        boost::filesystem::path timestamp_path = boost::filesystem::absolute(
                server_config.GetParameter("timestamp"),
                base_path
        );

        // check if data files empty
        if ( 0 == boost::filesystem::file_size( node_data_path ) ) {
            throw OSRMException("nodes file is empty");
        }
        if ( 0 == boost::filesystem::file_size( edge_data_path ) ) {
            throw OSRMException("edges file is empty");
        }

        //TODO: remove any previous data

        // Loading street names
        SimpleLogger().Write() << "Loading names index";
        uint64_t number_of_bytes = 0;
        boost::filesystem::ifstream name_stream(
            name_data_path, std::ios::binary
        );
        unsigned number_of_elements = 0;
        name_stream.read((char *)&number_of_elements, sizeof(unsigned));
        BOOST_ASSERT_MSG(0 != number_of_elements, "name file broken");
        StoreIntegerInSharedMemory(number_of_elements, NAME_INDEX_SIZE);
        number_of_bytes = sizeof(unsigned)*number_of_elements;

        SharedMemory * index_memory = SharedMemoryFactory::Get(
            NAMES_INDEX,
            number_of_bytes
        );
        unsigned * index_ptr = static_cast<unsigned *>( index_memory->Ptr() );
        name_stream.read((char*)index_ptr, number_of_bytes);

        SimpleLogger().Write() << "Loading names list";
        name_stream.read((char *)&number_of_bytes, sizeof(unsigned));
        StoreIntegerInSharedMemory(number_of_bytes, NAME_INDEX_SIZE);
        SharedMemory * char_memory  = SharedMemoryFactory::Get(
            NAMES_LIST, number_of_bytes+1
        );
        char * char_ptr = static_cast<char *>( char_memory->Ptr() );
        name_stream.read(char_ptr, number_of_bytes);
        name_stream.close();

        std::vector<QueryGraph::_StrNode> node_list;
        std::vector<QueryGraph::_StrEdge> edge_list;

        //TODO: Read directly into shared memory
        unsigned m_check_sum = 0;
        SimpleLogger().Write() << "Loading graph node list";
        uint64_t m_number_of_nodes = readHSGRFromStream(
            hsgr_path,
            node_list,
            edge_list,
            &m_check_sum
        );

        StoreIntegerInSharedMemory(node_list.size(), GRAPH_NODE_LIST_SIZE);
        SharedMemory * graph_node_memory  = SharedMemoryFactory::Get(
            GRAPH_NODE_LIST,
            sizeof(QueryGraph::_StrNode)*node_list.size()
        );
        QueryGraph::_StrNode * graph_node_ptr = static_cast<QueryGraph::_StrNode *>(
            graph_node_memory->Ptr()
        );

        std::copy(node_list.begin(), node_list.end(), graph_node_ptr);

        SimpleLogger().Write() << "Loading graph edge list";
        StoreIntegerInSharedMemory(edge_list.size(), GRAPH_EDGE_LIST_SIZE);
        SharedMemory * graph_edge_memory  = SharedMemoryFactory::Get(
            GRAPH_EDGE_LIST,
            sizeof(QueryGraph::_StrEdge)*edge_list.size()
        );
        QueryGraph::_StrEdge * graph_edge_ptr = static_cast<QueryGraph::_StrEdge *>(
            graph_edge_memory->Ptr()
        );
        std::copy(edge_list.begin(), edge_list.end(), graph_edge_ptr);

        // load checksum
        SimpleLogger().Write() << "Loading check sum";
        StoreIntegerInSharedMemory(m_check_sum, CHECK_SUM);

        SimpleLogger().Write() << "Loading timestamp";
        std::string m_timestamp;
        if( boost::filesystem::exists(timestamp_path) ) {
            boost::filesystem::ifstream timestampInStream( timestamp_path );
            if(!timestampInStream) {
                SimpleLogger().Write(logWARNING) << timestamp_path << " not found";
            }
            getline(timestampInStream, m_timestamp);
            timestampInStream.close();
        }
        if(m_timestamp.empty()) {
            m_timestamp = "n/a";
        }
        if(25 < m_timestamp.length()) {
            m_timestamp.resize(25);
        }
        StoreIntegerInSharedMemory(m_timestamp.length(), TIMESTAMP_SIZE);
        SharedMemory * timestamp_memory  = SharedMemoryFactory::Get(
            TIMESTAMP, m_timestamp.length()
        );
        char * timestamp_ptr = static_cast<char *>( timestamp_memory->Ptr() );
        std::copy(
            m_timestamp.c_str(),
            m_timestamp.c_str()+m_timestamp.length(),
            timestamp_ptr
        );

        //Loading information for original edges
        boost::filesystem::ifstream edges_input_stream(
            edge_data_path,
            std::ios::binary
        );
        unsigned number_of_edges = 0;
        edges_input_stream.read((char*)&number_of_edges, sizeof(unsigned));
        SimpleLogger().Write() << "Loading via node, coordinates and turn instruction list";
        StoreIntegerInSharedMemory(number_of_edges, NAME_ID_LIST_SIZE);
        StoreIntegerInSharedMemory(number_of_edges, TURN_INSTRUCTION_LIST_SIZE);
        StoreIntegerInSharedMemory(number_of_edges, VIA_NODE_LIST_SIZE);

        SharedMemory * name_id_memory  = SharedMemoryFactory::Get(
            NAME_ID_LIST,
            number_of_edges*sizeof(unsigned)
        );
        unsigned * name_id_ptr = static_cast<unsigned *>( name_id_memory->Ptr() );

        SharedMemory *via_node_memory  = SharedMemoryFactory::Get(
            VIA_NODE_LIST,
            number_of_edges*sizeof(unsigned)
        );
        unsigned * via_node_ptr = static_cast<unsigned *>( via_node_memory->Ptr() );

        SharedMemory *turn_instruction_memory  = SharedMemoryFactory::Get(
            TURN_INSTRUCTION_LIST,
            number_of_edges*sizeof(TurnInstruction)
        );
        unsigned * turn_instructions_ptr = static_cast<unsigned *>( turn_instruction_memory->Ptr() );

        OriginalEdgeData current_edge_data;
        for(unsigned i = 0; i < number_of_edges; ++i) {
            edges_input_stream.read(
                (char*)&(current_edge_data),
                sizeof(OriginalEdgeData)
            );
            via_node_ptr[i] = current_edge_data.viaNode;
            name_id_ptr[i]  = current_edge_data.nameID;
            turn_instructions_ptr[i] = current_edge_data.turnInstruction;
        }
        edges_input_stream.close();

        // Loading list of coordinates
        SimpleLogger().Write(logDEBUG) << "Loading coordinates list";
        boost::filesystem::ifstream nodes_input_stream(
            node_data_path,
            std::ios::binary
        );
        unsigned number_of_nodes = 0;
        nodes_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
        StoreIntegerInSharedMemory(number_of_nodes, COORDINATE_LIST_SIZE);

        SharedMemory *coordinates_memory  = SharedMemoryFactory::Get(
            COORDINATE_LIST,
            number_of_nodes*sizeof(FixedPointCoordinate)
        );
        FixedPointCoordinate * coordinates_ptr = static_cast<FixedPointCoordinate *>( coordinates_memory->Ptr() );

        NodeInfo current_node;
        for(unsigned i = 0; i < number_of_nodes; ++i) {
            nodes_input_stream.read((char *)&current_node, sizeof(NodeInfo));
            coordinates_ptr[i] = FixedPointCoordinate(current_node.lat, current_node.lon);
        }
        nodes_input_stream.close();

        // Loading r-tree search data structure
        SimpleLogger().Write() << "loading r-tree search list";
        boost::filesystem::ifstream tree_node_file(
            ram_index_path,
            std::ios::binary
        );

        uint32_t tree_size = 0;
        tree_node_file.read((char*)&tree_size, sizeof(uint32_t));
        StoreIntegerInSharedMemory(tree_size, R_SEARCH_TREE_SIZE);
        //SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " << (sizeof(TreeNode)*tree_size) << " bytes";
        SharedMemory * rtree_memory  = SharedMemoryFactory::Get(
            R_SEARCH_TREE,
            tree_size*sizeof(TreeNode);
        );
        char * rtree_ptr = static_cast<char *>( rtree_memory->Ptr() );

        tree_node_file.read(rtree_ptr, sizeof(TreeNode)*tree_size);
        tree_node_file.close();

    } catch(const std::exception & e) {
        SimpleLogger().Write(logWARNING) << "caught exception: " << e.what();
    }

    //

    return 0;
}
<|endoftext|>