地面站终端 App
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
14 KiB

/****************************************************************************
*
* (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()->rawValue().toBool()) {
valueSetIsDistance()->setRawValue(true);
}
} 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);
}