QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
Mixer.cc
Go to the documentation of this file.
1#include "Mixer.h"
2#include "ParameterManager.h"
4
5QGC_LOGGING_CATEGORY(MixerLog, "Vehicle.Actuators.Mixer")
6
7using namespace Mixer;
8
9ChannelConfigInstance* ChannelConfig::instantiate(int paramIndex, int actuatorTypeIndex,
10 ParameterManager* parameterManager, std::function<void(Function, Fact*)> factAddedCb)
11{
12 QString param = _parameter.param.name;
13 int usedParamIndex;
14 if (_isActuatorTypeConfig) {
15 usedParamIndex = actuatorTypeIndex + indexOffset();
16 } else {
17 usedParamIndex = paramIndex + indexOffset();
18 }
19 param.replace("${i}", QString::number(usedParamIndex));
20
21 Fact* fact = nullptr;
22 if (param == "" && !_isActuatorTypeConfig) { // constant value
23 float value = 0.f;
24 if (fixedValues().size() == 1) {
25 value = fixedValues()[0];
26 } else if (paramIndex < fixedValues().size()) {
27 value = fixedValues()[paramIndex];
28 }
29
31 metaData->setReadOnly(true);
32 metaData->setDecimalPlaces(4);
33 fact = new Fact("", metaData, this);
34 fact->setRawValue(value);
35
36 } else if (parameterManager->parameterExists(ParameterManager::defaultComponentId, param)) {
37 fact = parameterManager->getParameter(ParameterManager::defaultComponentId, param);
38 if (displayOption() == Parameter::DisplayOption::Bitset) {
39 fact = new FactBitset(this, fact, usedParamIndex);
40 } else if (displayOption() == Parameter::DisplayOption::BoolTrueIfPositive) {
41 fact = new FactFloatAsBool(this, fact);
42 }
43 factAddedCb(function(), fact);
44 } else {
45 qCDebug(MixerLog) << "ActuatorOutputChannel: Param does not exist:" << param;
46 }
47
48 ChannelConfigInstance* instance = new ChannelConfigInstance(this, fact, *this);
49 channelInstanceCreated(instance);
50 return instance;
51}
52
54{
55 _instances.append(instance);
57 this, &ChannelConfig::instanceVisibleChanged);
58}
59
60void ChannelConfig::instanceVisibleChanged()
61{
62 bool visible = false;
63 for (const auto& instance : _instances) {
64 if (instance->visible()) {
65 visible = true;
66 }
67 }
68
69 if (visible != _visible) {
70 _visible = visible;
71 emit visibleChanged();
72 }
73}
74
76 [[maybe_unused]] int paramIndex, [[maybe_unused]] int actuatorTypeIndex,
77 [[maybe_unused]] ParameterManager *parameterManager,
78 [[maybe_unused]] std::function<void(Function, Fact *)> factAddedCb)
79{
81 channelInstanceCreated(instance);
82 return instance;
83}
84
86{
87 for (int i = 0; i < configInstances->count(); ++i) {
88 auto channelConfigInstance = configInstances->value<ChannelConfigInstance*>(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;
95 }
96 }
97 Q_ASSERT(_axes[0] && _axes[1] && _axes[2]);
98
99 for (int i = 0; i < 3; ++i) {
100 if (!_axes[i]->fact())
101 return;
102 }
103
104 // Initialize 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};
109 metaData->setEnumInfo(enumStrings, enumValues);
110 _fact = new Fact("", metaData, this);
111 setFactFromAxes();
112
113 connect(_fact, &Fact::rawValueChanged, this, &ChannelConfigInstanceVirtualAxis::setAxesFromFact);
114 for (int i=0; i < 3; ++i) {
115 connect(_axes[i]->fact(), &Fact::rawValueChanged,
116 this, [this](){ ChannelConfigInstanceVirtualAxis::setFactFromAxes(true); });
117 }
118 // Inherit visibility & enabled from the first axis
119 connect(_axes[0], &ChannelConfigInstance::visibleChanged,
120 this, &ChannelConfigInstanceVirtualAxis::axisVisibleChanged);
121 connect(_axes[0], &ChannelConfigInstance::enabledChanged,
122 this, &ChannelConfigInstanceVirtualAxis::axisEnableChanged);
123 axisVisibleChanged();
124 axisEnableChanged();
125}
126
127void ChannelConfigInstanceVirtualAxis::axisVisibleChanged()
128{
129 if (_axes[0]->visibleRule() != visibleRule()) {
130 setVisibleRule(_axes[0]->visibleRule());
131 }
132}
133
134void ChannelConfigInstanceVirtualAxis::axisEnableChanged()
135{
136 if (_axes[0]->enabledRule() != enabledRule()) {
137 setEnabledRule(_axes[0]->enabledRule());
138 }
139}
140
141void ChannelConfigInstanceVirtualAxis::setFactFromAxes(bool keepVisible)
142{
143 if (_ignoreChange) {
144 return;
145 }
146 _ignoreChange = true;
147 float x = _axes[0]->fact()->rawValue().toFloat();
148 float y = _axes[1]->fact()->rawValue().toFloat();
149 float z = _axes[2]->fact()->rawValue().toFloat();
150 Direction direction{Direction::Custom}; // set to custom if no match
151 const float eps = 0.00001f;
152 if (fabsf(x) < eps && fabsf(y) < eps && fabsf(z + 1.f) < eps) {
153 direction = Direction::Upwards;
154 } else if (fabsf(x) < eps && fabsf(y) < eps && fabsf(z - 1.f) < eps) {
155 direction = Direction::Downwards;
156 } else if (fabsf(x - 1.f) < eps && fabsf(y) < eps && fabsf(z) < eps) {
157 direction = Direction::Forwards;
158 } else if (fabsf(x + 1.f) < eps && fabsf(y) < eps && fabsf(z) < eps) {
159 direction = Direction::Backwards;
160 } else if (fabsf(x) < eps && fabsf(y + 1.f) < eps && fabsf(z) < eps) {
161 direction = Direction::Leftwards;
162 } else if (fabsf(x) < eps && fabsf(y - 1.f) < eps && fabsf(z) < eps) {
163 direction = Direction::Rightwards;
164 }
165 _fact->setRawValue((uint32_t)direction);
166
167 bool visible = direction == Direction::Custom || keepVisible;
168 for(int i=0; i < 3; ++i) {
169 _axes[i]->setVisibleAxis(visible);
170 }
171 _ignoreChange = false;
172}
173
174void ChannelConfigInstanceVirtualAxis::setAxesFromFact()
175{
176 if (_ignoreChange) {
177 return;
178 }
179 _ignoreChange = true;
180 int directionIdx = _fact->rawValue().toInt();
181
182 if (directionIdx > 0) {
183 Direction direction = (Direction)directionIdx;
184 float x{}, y{}, z{};
185 switch (direction) {
187 x = 0.f; y = 0.f; z = -1.f;
188 break;
190 x = 0.f; y = 0.f; z = 1.f;
191 break;
193 x = 1.f; y = 0.f; z = 0.f;
194 break;
196 x = -1.f; y = 0.f; z = 0.f;
197 break;
199 x = 0.f; y = -1.f; z = 0.f;
200 break;
202 x = 0.f; y = 1.f; z = 0.f;
203 break;
205 break;
206 }
207 _axes[0]->fact()->setRawValue(x);
208 _axes[1]->fact()->setRawValue(y);
209 _axes[2]->fact()->setRawValue(z);
210 }
211
212
213 bool visible = directionIdx == 0;
214 for(int i=0; i < 3; ++i) {
215 _axes[i]->setVisibleAxis(visible);
216 }
217 _ignoreChange = false;
218}
219
220MixerChannel::MixerChannel(QObject *parent, const QString &label, int actuatorFunction, int paramIndex, int actuatorTypeIndex,
221 QmlObjectListModel &channelConfigs, ParameterManager* parameterManager, const Rule* rule,
222 std::function<void(Function, Fact*)> factAddedCb)
223 : QObject(parent), _label(label), _actuatorFunction(actuatorFunction), _paramIndex(paramIndex),
224 _actuatorTypeIndex(actuatorTypeIndex), _rule(rule)
225{
226 for (int i = 0; i < channelConfigs.count(); ++i) {
227 auto channelConfig = channelConfigs.value<ChannelConfig*>(i);
228
229 ChannelConfigInstance* instance = channelConfig->instantiate(paramIndex, actuatorTypeIndex, parameterManager, factAddedCb);
230 Fact* fact = instance->fact();
231
232 // if we have a valid rule, check the identifiers
233 if (rule) {
234 if (channelConfig->identifier() == rule->selectIdentifier) {
235 _ruleSelectIdentifierIdx = _configInstances->count();
236 if (fact) {
237 _currentSelectIdentifierValue = fact->rawValue().toInt();
238 }
239 } else {
240 for (int applyIndex = 0; applyIndex < rule->applyIdentifiers.size(); ++applyIndex) {
241 if (channelConfig->identifier() == rule->applyIdentifiers[applyIndex]) {
242 instance->setRuleApplyIdentifierIdx(applyIndex);
243 }
244 }
245 }
246
247 if (fact) {
248 connect(fact, &Fact::rawValueChanged, this, [this]() { applyRule(); });
249 }
250 }
251
252 _configInstances->append(instance);
253 }
254
255 for (int i = 0; i < _configInstances->count(); ++i) {
256 auto channelConfigInstance = _configInstances->value<ChannelConfigInstance*>(i);
257 channelConfigInstance->allInstancesInitialized(_configInstances);
258 }
259
260 applyRule(true);
261}
262
263void MixerChannel::applyRule(bool noConstraints)
264{
265 if (!_rule || _ruleSelectIdentifierIdx == -1 || _applyingRule) {
266 return;
267 }
268 _applyingRule = true; // prevent recursive signals
269
270 Fact* selectFact = _configInstances->value<ChannelConfigInstance*>(_ruleSelectIdentifierIdx)->fact();
271 if (selectFact && selectFact->type() == FactMetaData::valueTypeInt32) {
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) {
277 ChannelConfigInstance* configInstance = _configInstances->value<ChannelConfigInstance*>(i);
278 if (configInstance->fact() && configInstance->ruleApplyIdentifierIdx() >= 0) {
279 const Rule::RuleItem& ruleItem = items[configInstance->ruleApplyIdentifierIdx()];
280 double factValue = configInstance->fact()->rawValue().toDouble();
281 bool changed = false;
282 if (ruleItem.hasMin && factValue < ruleItem.min) {
283 factValue = ruleItem.min;
284 changed = true;
285 }
286 if (ruleItem.hasMax && factValue > ruleItem.max) {
287 factValue = ruleItem.max;
288 changed = true;
289 }
290 if (valueChanged && ruleItem.hasDefault) {
291 factValue = ruleItem.defaultVal;
292 changed = true;
293 }
294 if (changed && !noConstraints) {
295 // here we could notify the user that a constraint got applied...
296 configInstance->fact()->setRawValue(factValue);
297 }
298 configInstance->setVisibleRule(!ruleItem.hidden);
299 configInstance->setEnabledRule(!ruleItem.disabled);
300 }
301 }
302
303 } else {
304 // no rule set for this value, just reset
305 for (int i = 0; i < _configInstances->count(); ++i) {
306 ChannelConfigInstance* configInstance = _configInstances->value<ChannelConfigInstance*>(i);
307 configInstance->setVisibleRule(true);
308 configInstance->setEnabledRule(true);
309 }
310 }
311 _currentSelectIdentifierValue = value;
312 }
313 _applyingRule = false;
314}
315
317 ActuatorGeometry& geometry) const
318{
320 const auto iter = actuatorTypes.find(group.actuatorType);
321 if (iter == actuatorTypes.end()) {
322 return false;
323 }
324 geometry.index = _actuatorTypeIndex;
325 geometry.labelIndexOffset = iter->labelIndexOffset;
326 int numPositionAxis = 0;
327
328 for (int i = 0; i < _configInstances->count(); ++i) {
329 ChannelConfigInstance* configInstance = _configInstances->value<ChannelConfigInstance*>(i);
330 if (!configInstance->fact()) {
331 continue;
332 }
333 switch (configInstance->channelConfig()->function()) {
335 geometry.position.setX(configInstance->fact()->rawValue().toFloat());
336 ++numPositionAxis;
337 break;
339 geometry.position.setY(configInstance->fact()->rawValue().toFloat());
340 ++numPositionAxis;
341 break;
343 geometry.position.setZ(configInstance->fact()->rawValue().toFloat());
344 ++numPositionAxis;
345 break;
347 geometry.spinDirection = configInstance->fact()->rawValue().toBool() ?
349 break;
350 case Function::AxisX:
351 case Function::AxisY:
352 case Function::AxisZ:
353 case Function::Type:
355 break;
356 }
357 }
358
359 return numPositionAxis == 3;
360}
361
362Fact* MixerChannel::getFact([[maybe_unused]] Function function) const
363{
364 for (int i = 0; i < _configInstances->count(); ++i) {
365 ChannelConfigInstance* configInstance = _configInstances->value<ChannelConfigInstance*>(i);
366 if (configInstance->channelConfig()->function() == Function::Type) {
367 return configInstance->fact();
368 }
369 }
370 return nullptr;
371}
372
374{
375 _channelConfigs->append(channelConfig);
377}
378
380{
381 _channels->append(channel);
382 emit channelsChanged();
383}
384
386{
387 _params->append(param);
388}
389
390void Mixers::reset(const ActuatorTypes& actuatorTypes, const MixerOptions& mixerOptions,
391 const QMap<int, OutputFunction>& functions, const Rules& rules)
392{
393 _groups->clearAndDeleteContents();
394 _actuatorTypes = actuatorTypes;
395 _mixerOptions = mixerOptions;
396 _functions = functions;
397 _functionsSpecificLabel.clear();
398 _rules = rules;
399 _mixerConditions.clear();
400 for (const auto& mixerOption : _mixerOptions) {
401 _mixerConditions.append(Condition(mixerOption.option, _parameterManager, "mixer-option"));
402 }
403 update();
404}
405
407{
408 // clear first
409 _groups->clearAndDeleteContents();
410 _functionsSpecificLabel.clear();
411
412 unsubscribeFacts();
413
414 // find configured mixer
415 _selectedMixer = -1;
416 for (int i = 0; i < _mixerConditions.size(); ++i) {
417 if (_mixerConditions[i].evaluate()) {
418 _selectedMixer = i;
419 break;
420 }
421 }
422
423
424 if (_selectedMixer != -1) {
425
426 subscribeFact(_mixerConditions[_selectedMixer].fact());
427
428 qCDebug(MixerLog) << "selected mixer index:" << _selectedMixer;
429
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);
436 if (countFact) {
437 count = countFact->rawValue().toInt();
438 }
439 }
440
441 int actuatorTypeIndex = actuatorTypeCount.value(actuatorGroup.actuatorType, 0);
442
443 MixerConfigGroup* currentMixerGroup = new MixerConfigGroup(this, actuatorGroup);
444
445 // params
446 const auto actuatorType = _actuatorTypes.find(actuatorGroup.actuatorType);
447 if (actuatorType != _actuatorTypes.end()) {
448 for (const auto& perItemParam : actuatorType->perItemParams) {
449 MixerParameter param{};
450 param.param = perItemParam;
451 currentMixerGroup->addChannelConfig(new ChannelConfig(currentMixerGroup, param, true));
452 }
453 }
454
455 const Rule* selectedRule{nullptr}; // at most 1 rule can be applied
456 int axisIdx[3]{-1, -1, -1};
457 for (const auto& perItemParam : actuatorGroup.perItemParameters) {
458 currentMixerGroup->addChannelConfig(new ChannelConfig(currentMixerGroup, perItemParam, false));
459
460 if (perItemParam.function == Function::AxisX) {
461 axisIdx[0] = currentMixerGroup->channelConfigs()->count() - 1;
462 } else if (perItemParam.function == Function::AxisY) {
463 axisIdx[1] = currentMixerGroup->channelConfigs()->count() - 1;
464 } else if (perItemParam.function == Function::AxisZ) {
465 axisIdx[2] = currentMixerGroup->channelConfigs()->count() - 1;
466 }
467
468 if (!perItemParam.identifier.isEmpty()) {
469 for (const auto& rule : _rules) {
470 if (rule.selectIdentifier == perItemParam.identifier) {
471 selectedRule = &rule;
472 }
473 }
474 }
475 }
476
477 // Add virtual axis dropdown configuration param if all 3 axes are found
478 if (axisIdx[0] >= 0 && axisIdx[1] >= 0 && axisIdx[2] >= 0) {
479 ChannelConfig* axisXConfig = currentMixerGroup->channelConfigs()->value<ChannelConfig*>(axisIdx[0]);
480 MixerParameter parameter = axisXConfig->config(); // use axisX as base (somewhat arbitrary)
482 parameter.param.name = "";
483 parameter.param.label = tr("Axis");
484 parameter.identifier = "";
485 ChannelConfig* virtualChannelConfig = new ChannelConfigVirtualAxis(currentMixerGroup, parameter);
486 currentMixerGroup->channelConfigs()->insert(axisIdx[0], virtualChannelConfig);
487 }
488
489 // 'count' param
490 if (actuatorGroup.count != "") {
491 currentMixerGroup->setCountParam(new ConfigParameter(currentMixerGroup, getFact(actuatorGroup.count),
492 "", false));
493 }
494
495 for (int actuatorIdx = 0; actuatorIdx < count; ++actuatorIdx) {
496 QString label = "";
497 int actuatorFunction = 0;
498 if (actuatorType != _actuatorTypes.end()) {
499 actuatorFunction = actuatorType->functionMin + actuatorTypeIndex;
500 label = _functions.value(actuatorFunction).label;
501 if (label == "") {
502 qCWarning(MixerLog) << "No label for output function" << actuatorFunction;
503 }
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];
511 }
512 if (itemLabelPrefix != "") {
513 label = itemLabelPrefix + " (" + label + ")";
514 _functionsSpecificLabel[actuatorFunction] = itemLabelPrefix;
515 }
516 }
517 auto factAdded = [this](Function function, Fact* fact) {
518 // Type might change more than the geometry
519 subscribeFact(fact, function != Function::Type);
520 };
521 MixerChannel* channel = new MixerChannel(currentMixerGroup, label, actuatorFunction, actuatorIdx, actuatorTypeIndex,
522 *currentMixerGroup->channelConfigs(), _parameterManager, selectedRule, factAdded);
523 currentMixerGroup->addChannel(channel);
524 ++actuatorTypeIndex;
525 }
526
527 // config params
528 for (const auto& parameter : actuatorGroup.parameters) {
529 currentMixerGroup->addConfigParam(new ConfigParameter(currentMixerGroup, getFact(parameter.name),
530 parameter.label, parameter.advanced));
531 }
532
533 _groups->append(currentMixerGroup);
534 actuatorTypeCount[actuatorGroup.actuatorType] = actuatorTypeIndex;
535 }
536 }
537
538 emit groupsChanged();
539
540}
541
542QString Mixers::getSpecificLabelForFunction(int function) const
543{
544 // Try to get it from the actuator type param
545 Fact* typeFact = nullptr;
546 for (int mixerGroupIdx = 0; !typeFact && mixerGroupIdx < _groups->count(); ++mixerGroupIdx) {
547 Mixer::MixerConfigGroup* mixerGroup = _groups->value<Mixer::MixerConfigGroup*>(mixerGroupIdx);
548 for (int mixerChannelIdx = 0; !typeFact && mixerChannelIdx < mixerGroup->channels()->count(); ++mixerChannelIdx) {
549 Mixer::MixerChannel* mixerChannel = mixerGroup->channels()->value<Mixer::MixerChannel*>(mixerChannelIdx);
550
551 if (mixerChannel->actuatorFunction() != function) {
552 continue;
553 }
554
555 typeFact = mixerChannel->getFact(Function::Type);
556 }
557 }
558 if (typeFact) {
559 // Now check if we have multiple functions configured with the same type.
560 // If so, add the function label to disambiguate
561 for (int mixerGroupIdx = 0; mixerGroupIdx < _groups->count(); ++mixerGroupIdx) {
562 Mixer::MixerConfigGroup* mixerGroup = _groups->value<Mixer::MixerConfigGroup*>(mixerGroupIdx);
563 for (int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->channels()->count(); ++mixerChannelIdx) {
564 Mixer::MixerChannel* mixerChannel = mixerGroup->channels()->value<Mixer::MixerChannel*>(mixerChannelIdx);
565
566 if (mixerChannel->actuatorFunction() == function) {
567 continue;
568 }
569 Fact* typeFactOther = mixerChannel->getFact(Function::Type);
570 if (typeFactOther && typeFactOther->rawValue() == typeFact->rawValue()) {
571 return typeFact->enumOrValueString() + " (" + _functions.value(function).label +")";
572 }
573 }
574 }
575 return typeFact->enumOrValueString();
576 }
577
578 const auto iter = _functionsSpecificLabel.find(function);
579 if (iter == _functionsSpecificLabel.end()) {
580 return _functions.value(function).label;
581 }
582 return *iter;
583}
584
585QSet<int> Mixers::getFunctions(bool requiredOnly) const
586{
587 QSet<int> ret;
588 for (int mixerGroupIdx = 0; mixerGroupIdx < _groups->count(); ++mixerGroupIdx) {
589 Mixer::MixerConfigGroup* mixerGroup = _groups->value<Mixer::MixerConfigGroup*>(mixerGroupIdx);
590 if (!requiredOnly || mixerGroup->group().required) {
591 for (int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->channels()->count(); ++mixerChannelIdx) {
592 const Mixer::MixerChannel* mixerChannel = mixerGroup->channels()->value<Mixer::MixerChannel*>(mixerChannelIdx);
593 if (mixerChannel->actuatorFunction() != 0) {
594 ret.insert(mixerChannel->actuatorFunction());
595 }
596 }
597 }
598 }
599
600 return ret;
601}
602
604{
605 if (_selectedMixer == -1) {
606 return "";
607 }
608 return _mixerOptions[_selectedMixer].type;
609}
610
611QString Mixers::title() const
612{
613 if (_selectedMixer == -1) {
614 return "";
615 }
616 return _mixerOptions[_selectedMixer].title;
617}
618QString Mixers::helpUrl() const
619{
620 if (_selectedMixer == -1) {
621 return "";
622 }
623 return _mixerOptions[_selectedMixer].helpUrl;
624}
625
626Fact* Mixers::getFact(const QString& paramName)
627{
628 if (!_parameterManager->parameterExists(ParameterManager::defaultComponentId, paramName)) {
629 qCDebug(MixerLog) << "Mixers: Param does not exist:" << paramName;
630 return nullptr;
631 }
632 Fact* fact = _parameterManager->getParameter(ParameterManager::defaultComponentId, paramName);
633 subscribeFact(fact);
634 return fact;
635}
636
637void Mixers::subscribeFact(Fact* fact, bool geometry)
638{
639 if (geometry) {
640 if (fact && !_subscribedFactsGeometry.contains(fact)) {
642 _subscribedFactsGeometry.insert(fact);
643 }
644 } else {
645 if (fact && !_subscribedFacts.contains(fact)) {
646 connect(fact, &Fact::rawValueChanged, this, &Mixers::paramChanged);
647 _subscribedFacts.insert(fact);
648 }
649 }
650}
651
652void Mixers::unsubscribeFacts()
653{
654 for (Fact* fact : _subscribedFacts) {
655 disconnect(fact, &Fact::rawValueChanged, this, &Mixers::paramChanged);
656 }
657 _subscribedFacts.clear();
658
659 for (Fact* fact : _subscribedFactsGeometry) {
660 disconnect(fact, &Fact::rawValueChanged, this, &Mixers::geometryParamChanged);
661 }
662 _subscribedFactsGeometry.clear();
663}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Holds the meta data associated with a Fact.
void setDecimalPlaces(int decimalPlaces)
void setEnumInfo(const QStringList &strings, const QVariantList &values)
void setReadOnly(bool bValue)
A Fact is used to hold a single value within the system.
Definition Fact.h:17
QString enumOrValueString()
Definition Fact.cc:784
void rawValueChanged(const QVariant &value)
FactMetaData::ValueType_t type() const
Definition Fact.h:124
void setRawValue(const QVariant &value)
Definition Fact.cc:128
QString label() const
Definition Fact.cc:484
QVariant rawValue() const
Value after translation.
Definition Fact.h:85
void allInstancesInitialized(QmlObjectListModel *configInstances) override
Definition Mixer.cc:85
bool visibleRule() const
Definition Mixer.h:206
int ruleApplyIdentifierIdx() const
Definition Mixer.h:214
void setVisibleAxis(bool visible)
Definition Mixer.h:212
virtual void allInstancesInitialized(QmlObjectListModel *configInstances)
Definition Mixer.h:217
bool enabledRule() const
Definition Mixer.h:207
ChannelConfig * channelConfig() const
Definition Mixer.h:199
void setEnabledRule(bool enabled)
Definition Mixer.h:210
void setVisibleRule(bool visible)
Definition Mixer.h:209
ChannelConfigInstance * instantiate(int paramIndex, int actuatorTypeIndex, ParameterManager *parameterManager, std::function< void(Function, Fact *)> factAddedCb) override
Definition Mixer.cc:75
bool visible() const
Definition Mixer.h:143
const MixerParameter & config() const
Definition Mixer.h:152
void channelInstanceCreated(ChannelConfigInstance *instance)
Definition Mixer.cc:53
Function function() const
Definition Mixer.h:139
int actuatorFunction() const
Definition Mixer.h:277
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)
Definition Mixer.cc:220
bool getGeometry(const ActuatorTypes &actuatorTypes, const MixerOption::ActuatorGroup &group, ActuatorGeometry &geometry) const
Definition Mixer.cc:316
void applyRule(bool noConstraints=false)
Definition Mixer.cc:263
Fact * getFact(Function function) const
Definition Mixer.cc:362
QmlObjectListModel * channelConfigs()
Definition Mixer.h:322
const MixerOption::ActuatorGroup & group() const
Definition Mixer.h:334
void setCountParam(ConfigParameter *param)
Definition Mixer.h:332
void addConfigParam(ConfigParameter *param)
Definition Mixer.cc:385
void addChannelConfig(ChannelConfig *channelConfig)
Definition Mixer.cc:373
QmlObjectListModel * channels()
Definition Mixer.h:325
void addChannel(MixerChannel *channel)
Definition Mixer.cc:379
const ActuatorTypes & actuatorTypes() const
Definition Mixer.h:378
QString configuredType() const
Definition Mixer.cc:603
void update()
Definition Mixer.cc:406
void groupsChanged()
const QMap< int, OutputFunction > & functions() const
Definition Mixer.h:396
void reset(const ActuatorTypes &actuatorTypes, const MixerOptions &mixerOptions, const QMap< int, OutputFunction > &functions, const Rules &rules)
Definition Mixer.cc:390
QString getSpecificLabelForFunction(int function) const
Definition Mixer.cc:542
QString title() const
Definition Mixer.cc:611
void geometryParamChanged()
void paramChanged()
QString helpUrl() const
Definition Mixer.cc:618
QSet< int > getFunctions(bool requiredOnly) const
Definition Mixer.cc:585
bool parameterExists(int componentId, const QString &paramName) const
Fact * getParameter(int componentId, const QString &paramName)
static constexpr int defaultComponentId
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
T value(int index) const
int count() const override final
void clearAndDeleteContents() override final
Clears the list and calls deleteLater on each entry.
void insert(int index, QObject *object)
Definition Mixer.h:12
Function
Definition Mixer.h:14
@ SpinDirection
CCW = true or 1.
QList< Rule > Rules
Definition Mixer.h:95
QList< MixerOption > MixerOptions
Definition Mixer.h:76
QMap< QString, ActuatorType > ActuatorTypes
key is the group name, where 'DEFAULT' is the default group
Definition Mixer.h:52
int labelIndexOffset
Definition Common.h:142
static Type typeFromStr(const QString &type)
Definition Common.cc:244
QVector3D position
Definition Common.h:143
SpinDirection spinDirection
Definition Common.h:144
bool required
if true, actuator has to be configured for a valid setup
Definition Mixer.h:64
Function function
Definition Mixer.h:28
Parameter param
Definition Mixer.h:27
QList< QString > applyIdentifiers
Definition Mixer.h:91
QMap< int, QList< RuleItem > > items
Definition Mixer.h:92
QString selectIdentifier
Definition Mixer.h:90
@ Bitset
integer displayed as boolean (checkbox), where the index defines the bit
@ BoolTrueIfPositive
Show checkbox for float/int value.