12 QString param = _parameter.param.name;
14 if (_isActuatorTypeConfig) {
15 usedParamIndex = actuatorTypeIndex + indexOffset();
17 usedParamIndex = paramIndex + indexOffset();
19 param.replace(
"${i}", QString::number(usedParamIndex));
22 if (param ==
"" && !_isActuatorTypeConfig) {
24 if (fixedValues().size() == 1) {
25 value = fixedValues()[0];
26 }
else if (paramIndex < fixedValues().size()) {
27 value = fixedValues()[paramIndex];
33 fact =
new Fact(
"", metaData,
this);
39 fact =
new FactBitset(
this, fact, usedParamIndex);
43 factAddedCb(function(), fact);
45 qCDebug(MixerLog) <<
"ActuatorOutputChannel: Param does not exist:" << param;
49 channelInstanceCreated(instance);
55 _instances.append(instance);
57 this, &ChannelConfig::instanceVisibleChanged);
60void ChannelConfig::instanceVisibleChanged()
63 for (
const auto& instance : _instances) {
64 if (instance->visible()) {
76 [[maybe_unused]]
int paramIndex, [[maybe_unused]]
int actuatorTypeIndex,
78 [[maybe_unused]] std::function<
void(
Function,
Fact *)> factAddedCb)
87 for (
int i = 0; i < configInstances->
count(); ++i) {
89 if (channelConfigInstance->channelConfig()->function() ==
Function::AxisX) {
90 _axes[0] = channelConfigInstance;
91 }
else if (channelConfigInstance->channelConfig()->function() ==
Function::AxisY) {
92 _axes[1] = channelConfigInstance;
93 }
else if (channelConfigInstance->channelConfig()->function() ==
Function::AxisZ) {
94 _axes[2] = channelConfigInstance;
97 Q_ASSERT(_axes[0] && _axes[1] && _axes[2]);
99 for (
int i = 0; i < 3; ++i) {
100 if (!_axes[i]->
fact())
105 QStringList enumStrings{tr(
"Custom"), tr(
"Upwards"), tr(
"Downwards"), tr(
"Forwards"), tr(
"Backwards"),
106 tr(
"Leftwards"), tr(
"Rightwards")};
107 QVariantList enumValues{0, 1, 2, 3, 4, 5, 6};
114 for (
int i=0; i < 3; ++i) {
116 this, [
this](){ ChannelConfigInstanceVirtualAxis::setFactFromAxes(
true); });
120 this, &ChannelConfigInstanceVirtualAxis::axisVisibleChanged);
122 this, &ChannelConfigInstanceVirtualAxis::axisEnableChanged);
123 axisVisibleChanged();
127void ChannelConfigInstanceVirtualAxis::axisVisibleChanged()
134void ChannelConfigInstanceVirtualAxis::axisEnableChanged()
141void ChannelConfigInstanceVirtualAxis::setFactFromAxes(
bool keepVisible)
146 _ignoreChange =
true;
151 const float eps = 0.00001f;
152 if (fabsf(x) < eps && fabsf(y) < eps && fabsf(z + 1.f) < eps) {
154 }
else if (fabsf(x) < eps && fabsf(y) < eps && fabsf(z - 1.f) < eps) {
156 }
else if (fabsf(x - 1.f) < eps && fabsf(y) < eps && fabsf(z) < eps) {
158 }
else if (fabsf(x + 1.f) < eps && fabsf(y) < eps && fabsf(z) < eps) {
160 }
else if (fabsf(x) < eps && fabsf(y + 1.f) < eps && fabsf(z) < eps) {
162 }
else if (fabsf(x) < eps && fabsf(y - 1.f) < eps && fabsf(z) < eps) {
168 for(
int i=0; i < 3; ++i) {
171 _ignoreChange =
false;
174void ChannelConfigInstanceVirtualAxis::setAxesFromFact()
179 _ignoreChange =
true;
182 if (directionIdx > 0) {
187 x = 0.f; y = 0.f; z = -1.f;
190 x = 0.f; y = 0.f; z = 1.f;
193 x = 1.f; y = 0.f; z = 0.f;
196 x = -1.f; y = 0.f; z = 0.f;
199 x = 0.f; y = -1.f; z = 0.f;
202 x = 0.f; y = 1.f; z = 0.f;
213 bool visible = directionIdx == 0;
214 for(
int i=0; i < 3; ++i) {
217 _ignoreChange =
false;
223 : QObject(parent), _label(label), _actuatorFunction(actuatorFunction), _paramIndex(paramIndex),
224 _actuatorTypeIndex(actuatorTypeIndex), _rule(rule)
226 for (
int i = 0; i < channelConfigs.
count(); ++i) {
229 ChannelConfigInstance* instance = channelConfig->instantiate(paramIndex, actuatorTypeIndex, parameterManager, factAddedCb);
230 Fact* fact = instance->fact();
235 _ruleSelectIdentifierIdx = _configInstances->
count();
237 _currentSelectIdentifierValue = fact->
rawValue().toInt();
240 for (
int applyIndex = 0; applyIndex < rule->
applyIdentifiers.size(); ++applyIndex) {
242 instance->setRuleApplyIdentifierIdx(applyIndex);
252 _configInstances->
append(instance);
255 for (
int i = 0; i < _configInstances->
count(); ++i) {
265 if (!_rule || _ruleSelectIdentifierIdx == -1 || _applyingRule) {
268 _applyingRule =
true;
272 const int value = selectFact->
rawValue().toInt();
273 if (_rule->
items.contains(value)) {
274 bool valueChanged = value != _currentSelectIdentifierValue;
275 const auto& items = _rule->
items[value];
276 for (
int i = 0; i < _configInstances->
count(); ++i) {
280 double factValue = configInstance->
fact()->
rawValue().toDouble();
281 bool changed =
false;
282 if (ruleItem.
hasMin && factValue < ruleItem.
min) {
283 factValue = ruleItem.
min;
286 if (ruleItem.
hasMax && factValue > ruleItem.
max) {
287 factValue = ruleItem.
max;
294 if (changed && !noConstraints) {
305 for (
int i = 0; i < _configInstances->
count(); ++i) {
311 _currentSelectIdentifierValue = value;
313 _applyingRule =
false;
320 const auto iter = actuatorTypes.find(group.
actuatorType);
321 if (iter == actuatorTypes.end()) {
324 geometry.
index = _actuatorTypeIndex;
326 int numPositionAxis = 0;
328 for (
int i = 0; i < _configInstances->
count(); ++i) {
330 if (!configInstance->
fact()) {
359 return numPositionAxis == 3;
364 for (
int i = 0; i < _configInstances->
count(); ++i) {
367 return configInstance->
fact();
375 _channelConfigs->
append(channelConfig);
381 _channels->
append(channel);
391 const QMap<int, OutputFunction>& functions,
const Rules& rules)
395 _mixerOptions = mixerOptions;
397 _functionsSpecificLabel.clear();
399 _mixerConditions.clear();
400 for (
const auto& mixerOption : _mixerOptions) {
401 _mixerConditions.append(
Condition(mixerOption.option, _parameterManager,
"mixer-option"));
410 _functionsSpecificLabel.clear();
416 for (
int i = 0; i < _mixerConditions.size(); ++i) {
417 if (_mixerConditions[i].evaluate()) {
424 if (_selectedMixer != -1) {
426 subscribeFact(_mixerConditions[_selectedMixer].fact());
428 qCDebug(MixerLog) <<
"selected mixer index:" << _selectedMixer;
430 const auto& actuatorGroups = _mixerOptions[_selectedMixer].actuators;
431 QMap<QString, int> actuatorTypeCount;
432 for (
const auto &actuatorGroup : actuatorGroups) {
433 int count = actuatorGroup.fixedCount;
434 if (actuatorGroup.count !=
"") {
435 Fact* countFact = getFact(actuatorGroup.count);
437 count = countFact->
rawValue().toInt();
441 int actuatorTypeIndex = actuatorTypeCount.value(actuatorGroup.actuatorType, 0);
446 const auto actuatorType = _actuatorTypes.find(actuatorGroup.actuatorType);
447 if (actuatorType != _actuatorTypes.end()) {
448 for (
const auto& perItemParam : actuatorType->perItemParams) {
450 param.
param = perItemParam;
455 const Rule* selectedRule{
nullptr};
456 int axisIdx[3]{-1, -1, -1};
457 for (
const auto& perItemParam : actuatorGroup.perItemParameters) {
468 if (!perItemParam.identifier.isEmpty()) {
469 for (
const auto& rule : _rules) {
471 selectedRule = &rule;
478 if (axisIdx[0] >= 0 && axisIdx[1] >= 0 && axisIdx[2] >= 0) {
482 parameter.param.name =
"";
483 parameter.param.label = tr(
"Axis");
484 parameter.identifier =
"";
490 if (actuatorGroup.count !=
"") {
495 for (
int actuatorIdx = 0; actuatorIdx < count; ++actuatorIdx) {
497 int actuatorFunction = 0;
498 if (actuatorType != _actuatorTypes.end()) {
499 actuatorFunction = actuatorType->functionMin + actuatorTypeIndex;
500 label = _functions.value(actuatorFunction).label;
502 qCWarning(MixerLog) <<
"No label for output function" << actuatorFunction;
504 QString itemLabelPrefix{};
505 if (actuatorGroup.itemLabelPrefix.size() == 1) {
506 QString paramIndex = QString::number(actuatorIdx + 1);
507 itemLabelPrefix = actuatorGroup.itemLabelPrefix[0];
508 itemLabelPrefix.replace(
"${i}", paramIndex);
509 }
else if (actuatorIdx < actuatorGroup.itemLabelPrefix.size()) {
510 itemLabelPrefix = actuatorGroup.itemLabelPrefix[actuatorIdx];
512 if (itemLabelPrefix !=
"") {
513 label = itemLabelPrefix +
" (" + label +
")";
514 _functionsSpecificLabel[actuatorFunction] = itemLabelPrefix;
517 auto factAdded = [
this](
Function function,
Fact* fact) {
521 MixerChannel* channel =
new MixerChannel(currentMixerGroup, label, actuatorFunction, actuatorIdx, actuatorTypeIndex,
522 *currentMixerGroup->
channelConfigs(), _parameterManager, selectedRule, factAdded);
528 for (
const auto& parameter : actuatorGroup.parameters) {
530 parameter.
label, parameter.advanced));
533 _groups->
append(currentMixerGroup);
534 actuatorTypeCount[actuatorGroup.actuatorType] = actuatorTypeIndex;
545 Fact* typeFact =
nullptr;
546 for (
int mixerGroupIdx = 0; !typeFact && mixerGroupIdx < _groups->
count(); ++mixerGroupIdx) {
548 for (
int mixerChannelIdx = 0; !typeFact && mixerChannelIdx < mixerGroup->
channels()->
count(); ++mixerChannelIdx) {
561 for (
int mixerGroupIdx = 0; mixerGroupIdx < _groups->
count(); ++mixerGroupIdx) {
563 for (
int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->
channels()->
count(); ++mixerChannelIdx) {
571 return typeFact->
enumOrValueString() +
" (" + _functions.value(function).label +
")";
578 const auto iter = _functionsSpecificLabel.find(function);
579 if (iter == _functionsSpecificLabel.end()) {
580 return _functions.value(function).label;
588 for (
int mixerGroupIdx = 0; mixerGroupIdx < _groups->
count(); ++mixerGroupIdx) {
591 for (
int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->
channels()->
count(); ++mixerChannelIdx) {
605 if (_selectedMixer == -1) {
608 return _mixerOptions[_selectedMixer].type;
613 if (_selectedMixer == -1) {
616 return _mixerOptions[_selectedMixer].title;
620 if (_selectedMixer == -1) {
623 return _mixerOptions[_selectedMixer].helpUrl;
626Fact* Mixers::getFact(
const QString& paramName)
629 qCDebug(MixerLog) <<
"Mixers: Param does not exist:" << paramName;
637void Mixers::subscribeFact(
Fact* fact,
bool geometry)
640 if (fact && !_subscribedFactsGeometry.contains(fact)) {
642 _subscribedFactsGeometry.insert(fact);
645 if (fact && !_subscribedFacts.contains(fact)) {
647 _subscribedFacts.insert(fact);
652void Mixers::unsubscribeFacts()
654 for (
Fact* fact : _subscribedFacts) {
657 _subscribedFacts.clear();
659 for (
Fact* fact : _subscribedFactsGeometry) {
662 _subscribedFactsGeometry.clear();
#define QGC_LOGGING_CATEGORY(name, categoryStr)
A Fact is used to hold a single value within the system.
QString enumOrValueString()
void rawValueChanged(const QVariant &value)
FactMetaData::ValueType_t type() const
void setRawValue(const QVariant &value)
QVariant rawValue() const
Value after translation.
void allInstancesInitialized(QmlObjectListModel *configInstances) override
int ruleApplyIdentifierIdx() const
void setVisibleAxis(bool visible)
virtual void allInstancesInitialized(QmlObjectListModel *configInstances)
ChannelConfig * channelConfig() const
void setEnabledRule(bool enabled)
void setVisibleRule(bool visible)
ChannelConfigInstance * instantiate(int paramIndex, int actuatorTypeIndex, ParameterManager *parameterManager, std::function< void(Function, Fact *)> factAddedCb) override
const MixerParameter & config() const
void channelInstanceCreated(ChannelConfigInstance *instance)
Function function() const
int actuatorFunction() const
MixerChannel(QObject *parent, const QString &label, int actuatorFunction, int paramIndex, int actuatorTypeIndex, QmlObjectListModel &channelConfigs, ParameterManager *parameterManager, const Rule *rule, std::function< void(Function, Fact *)> factAddedCb)
bool getGeometry(const ActuatorTypes &actuatorTypes, const MixerOption::ActuatorGroup &group, ActuatorGeometry &geometry) const
void applyRule(bool noConstraints=false)
Fact * getFact(Function function) const
QmlObjectListModel * channelConfigs()
const MixerOption::ActuatorGroup & group() const
void setCountParam(ConfigParameter *param)
void addConfigParam(ConfigParameter *param)
void addChannelConfig(ChannelConfig *channelConfig)
QmlObjectListModel * channels()
void channelConfigsChanged()
void addChannel(MixerChannel *channel)
const ActuatorTypes & actuatorTypes() const
QString configuredType() const
const QMap< int, OutputFunction > & functions() const
void reset(const ActuatorTypes &actuatorTypes, const MixerOptions &mixerOptions, const QMap< int, OutputFunction > &functions, const Rules &rules)
QString getSpecificLabelForFunction(int function) const
void geometryParamChanged()
QSet< int > getFunctions(bool requiredOnly) const
bool parameterExists(int componentId, const QString ¶mName) const
Fact * getParameter(int componentId, const QString ¶mName)
static constexpr int defaultComponentId
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
int count() const override final
void clearAndDeleteContents() override final
Clears the list and calls deleteLater on each entry.
void insert(int index, QObject *object)
@ SpinDirection
CCW = true or 1.
QList< MixerOption > MixerOptions
QMap< QString, ActuatorType > ActuatorTypes
key is the group name, where 'DEFAULT' is the default group
static Type typeFromStr(const QString &type)
SpinDirection spinDirection
bool required
if true, actuator has to be configured for a valid setup
QList< QString > applyIdentifiers
QMap< int, QList< RuleItem > > items
@ Bitset
integer displayed as boolean (checkbox), where the index defines the bit
@ BoolTrueIfPositive
Show checkbox for float/int value.