CameraCalc.cc 13.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/****************************************************************************
 *
 *   (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>

17 18 19 20 21 22 23 24 25 26
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";

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

29
CameraCalc::CameraCalc(Vehicle* vehicle, QString settingsGroup, QObject* parent)
30 31 32 33
    : CameraSpec                    (parent)
    , _vehicle                      (vehicle)
    , _dirty                        (false)
    , _disableRecalc                (false)
34
    , _distanceToSurfaceRelative    (true)
35
    , _metaDataMap                  (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraCalc.FactMetaData.json"), this))
36 37 38 39 40 41 42 43
    , _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])
44 45 46 47 48 49
    , _imageFootprintSide           (0)
    , _imageFootprintFrontal        (0)
    , _knownCameraList              (_vehicle->staticCameraList())
{
    QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);

50 51 52 53 54 55 56
    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);
57
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::_setDirty);
58 59
    connect(this,                           &CameraCalc::distanceToSurfaceRelativeChanged,  this, &CameraCalc::_setDirty);

60 61 62
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::_cameraNameChanged);
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::isManualCameraChanged);
    connect(&_cameraNameFact,               &Fact::valueChanged,                            this, &CameraCalc::isCustomCameraChanged);
63 64 65 66 67 68 69

    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(landscape(),                &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);

70
    _cameraNameChanged();
DonLakeFlyer's avatar
DonLakeFlyer committed
71 72

    setDirty(false);
73 74 75 76 77 78 79 80 81 82
}

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

83
void CameraCalc::_cameraNameChanged(void)
84
{
85 86 87
    if (_disableRecalc) {
        return;
    }
88

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    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()) {
122 123 124
            // These values are unknown for these types
            fixedOrientation()->setRawValue(false);
            minTriggerInterval()->setRawValue(0);
125
            if (isManualCamera()) {
126
                valueSetIsDistance()->setRawValue(false);
127 128
            }
        } else {
129
            qWarning() << "Internal Error: Not known camera, but now manual or custom either";
130 131
        }
    }
132 133 134 135
    _disableRecalc = false;

    _recalcTriggerDistance();
    _adjustDistanceToSurfaceRelative();
136 137 138 139
}

void CameraCalc::_recalcTriggerDistance(void)
{
140
    if (_disableRecalc || isManualCamera()) {
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
        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
{
183
    json[JsonHelper::jsonVersionKey] =      1;
184 185 186 187 188
    json[adjustedFootprintSideName] =       _adjustedFootprintSideFact.rawValue().toDouble();
    json[adjustedFootprintFrontalName] =    _adjustedFootprintFrontalFact.rawValue().toDouble();
    json[distanceToSurfaceName] =           _distanceToSurfaceFact.rawValue().toDouble();
    json[distanceToSurfaceRelativeName] =   _distanceToSurfaceRelative;
    json[cameraNameName] =                  _cameraNameFact.rawValue().toString();
189

190
    if (!isManualCamera()) {
191
        CameraSpec::save(json);
192 193 194 195
        json[valueSetIsDistanceName] = _valueSetIsDistanceFact.rawValue().toBool();
        json[imageDensityName] =       _imageDensityFact.rawValue().toDouble();
        json[frontalOverlapName] =     _frontalOverlapFact.rawValue().toDouble();
        json[sideOverlapName] =        _sideOverlapFact.rawValue().toDouble();
196 197 198
    }
}

199
bool CameraCalc::load(const QJsonObject& json, QString& errorString)
200 201 202 203 204 205 206 207 208 209
{
    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) {
210
            v1Json[cameraNameName] = customCameraName();
211
        } else if (cameraSpec == CameraSpecNone) {
212
            v1Json[cameraNameName] = manualCameraName();
213 214 215 216 217 218 219 220 221 222 223
        }
        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;
    }

224
    QList<JsonHelper::KeyValidateInfo> keyInfoList1 = {
225 226 227 228 229
        { cameraNameName,                   QJsonValue::String, true },
        { adjustedFootprintSideName,        QJsonValue::Double, true },
        { adjustedFootprintFrontalName,     QJsonValue::Double, true },
        { distanceToSurfaceName,            QJsonValue::Double, true },
        { distanceToSurfaceRelativeName,    QJsonValue::Bool, true },
230
    };
231
    if (!JsonHelper::validateKeys(v1Json, keyInfoList1, errorString)) {
232 233 234
        return false;
    }

235
    _disableRecalc = true;
236

237 238 239 240
    _cameraNameFact.setRawValue                 (v1Json[cameraNameName].toString());
    _adjustedFootprintSideFact.setRawValue      (v1Json[adjustedFootprintSideName].toDouble());
    _adjustedFootprintFrontalFact.setRawValue   (v1Json[adjustedFootprintFrontalName].toDouble());
    _distanceToSurfaceFact.setRawValue          (v1Json[distanceToSurfaceName].toDouble());
241

242
    _distanceToSurfaceRelative = v1Json[distanceToSurfaceRelativeName].toBool();
243

244
    if (!isManualCamera()) {
245
        QList<JsonHelper::KeyValidateInfo> keyInfoList2 = {
246 247 248 249
            { valueSetIsDistanceName,   QJsonValue::Bool,   true },
            { imageDensityName,         QJsonValue::Double, true },
            { frontalOverlapName,       QJsonValue::Double, true },
            { sideOverlapName,          QJsonValue::Double, true },
250
        };
251
        if (!JsonHelper::validateKeys(v1Json, keyInfoList2, errorString)) {
252
            return false;
253
            _disableRecalc = false;
254 255
        }

256 257 258 259
        _valueSetIsDistanceFact.setRawValue (v1Json[valueSetIsDistanceName].toBool());
        _imageDensityFact.setRawValue       (v1Json[imageDensityName].toDouble());
        _frontalOverlapFact.setRawValue     (v1Json[frontalOverlapName].toDouble());
        _sideOverlapFact.setRawValue        (v1Json[sideOverlapName].toDouble());
260

261
        if (!CameraSpec::load(v1Json, errorString)) {
262 263 264 265
            return false;
        }
    }

266
    _disableRecalc = false;
267 268 269

    return true;
}
270 271 272 273 274 275 276 277 278 279

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

QString CameraCalc::manualCameraName(void)
{
    return tr("Manual (no camera specs)");
}
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

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

void CameraCalc::setDistanceToSurfaceRelative(bool distanceToSurfaceRelative)
{
    if (distanceToSurfaceRelative != _distanceToSurfaceRelative) {
        _distanceToSurfaceRelative = distanceToSurfaceRelative;
        emit distanceToSurfaceRelativeChanged(distanceToSurfaceRelative);
    }
}
295 296 297 298 299

void CameraCalc::_setDirty(void)
{
    setDirty(true);
}