11 if (_isActuatorTypeConfig) {
16 param.replace(
"${i}", QString::number(usedParamIndex));
19 if (param ==
"" && !_isActuatorTypeConfig) {
30 fact =
new Fact(
"", metaData,
this);
31 fact->setRawValue(value);
36 fact =
new FactBitset(
this, fact, usedParamIndex);
42 qCDebug(ActuatorsConfigLog) <<
"ActuatorOutputChannel: Param does not exist:" << param;
52 _instances.append(instance);
54 this, &ChannelConfig::instanceVisibleChanged);
57void ChannelConfig::instanceVisibleChanged()
60 for (
const auto& instance : _instances) {
61 if (instance->visible()) {
73 [[maybe_unused]]
int paramIndex, [[maybe_unused]]
int actuatorTypeIndex,
75 [[maybe_unused]] std::function<
void(
Function,
Fact *)> factAddedCb)
84 for (
int i = 0; i < configInstances->
count(); ++i) {
86 if (channelConfigInstance->channelConfig()->function() ==
Function::AxisX) {
87 _axes[0] = channelConfigInstance;
88 }
else if (channelConfigInstance->channelConfig()->function() ==
Function::AxisY) {
89 _axes[1] = channelConfigInstance;
90 }
else if (channelConfigInstance->channelConfig()->function() ==
Function::AxisZ) {
91 _axes[2] = channelConfigInstance;
94 Q_ASSERT(_axes[0] && _axes[1] && _axes[2]);
96 for (
int i = 0; i < 3; ++i) {
97 if (!_axes[i]->
fact())
102 QStringList enumStrings{tr(
"Custom"), tr(
"Upwards"), tr(
"Downwards"), tr(
"Forwards"), tr(
"Backwards"),
103 tr(
"Leftwards"), tr(
"Rightwards")};
104 QVariantList enumValues{0, 1, 2, 3, 4, 5, 6};
111 for (
int i=0; i < 3; ++i) {
113 this, [
this](){ ChannelConfigInstanceVirtualAxis::setFactFromAxes(
true); });
117 this, &ChannelConfigInstanceVirtualAxis::axisVisibleChanged);
119 this, &ChannelConfigInstanceVirtualAxis::axisEnableChanged);
120 axisVisibleChanged();
124void ChannelConfigInstanceVirtualAxis::axisVisibleChanged()
131void ChannelConfigInstanceVirtualAxis::axisEnableChanged()
138void ChannelConfigInstanceVirtualAxis::setFactFromAxes(
bool keepVisible)
143 _ignoreChange =
true;
144 float x = _axes[0]->
fact()->rawValue().toFloat();
145 float y = _axes[1]->
fact()->rawValue().toFloat();
146 float z = _axes[2]->
fact()->rawValue().toFloat();
148 const float eps = 0.00001f;
149 if (fabsf(x) < eps && fabsf(y) < eps && fabsf(z + 1.f) < eps) {
151 }
else if (fabsf(x) < eps && fabsf(y) < eps && fabsf(z - 1.f) < eps) {
153 }
else if (fabsf(x - 1.f) < eps && fabsf(y) < eps && fabsf(z) < eps) {
155 }
else if (fabsf(x + 1.f) < eps && fabsf(y) < eps && fabsf(z) < eps) {
157 }
else if (fabsf(x) < eps && fabsf(y + 1.f) < eps && fabsf(z) < eps) {
159 }
else if (fabsf(x) < eps && fabsf(y - 1.f) < eps && fabsf(z) < eps) {
162 _fact->setRawValue((uint32_t)direction);
165 for(
int i=0; i < 3; ++i) {
168 _ignoreChange =
false;
171void ChannelConfigInstanceVirtualAxis::setAxesFromFact()
176 _ignoreChange =
true;
177 int directionIdx =
_fact->rawValue().toInt();
179 if (directionIdx > 0) {
184 x = 0.f; y = 0.f; z = -1.f;
187 x = 0.f; y = 0.f; z = 1.f;
190 x = 1.f; y = 0.f; z = 0.f;
193 x = -1.f; y = 0.f; z = 0.f;
196 x = 0.f; y = -1.f; z = 0.f;
199 x = 0.f; y = 1.f; z = 0.f;
204 _axes[0]->
fact()->setRawValue(x);
205 _axes[1]->
fact()->setRawValue(y);
206 _axes[2]->
fact()->setRawValue(z);
210 bool visible = directionIdx == 0;
211 for(
int i=0; i < 3; ++i) {
214 _ignoreChange =
false;
220 : QObject(parent), _label(label), _actuatorFunction(actuatorFunction), _paramIndex(paramIndex),
221 _actuatorTypeIndex(actuatorTypeIndex), _rule(rule)
223 for (
int i = 0; i < channelConfigs.
count(); ++i) {
226 ChannelConfigInstance* instance = channelConfig->instantiate(paramIndex, actuatorTypeIndex, parameterManager, factAddedCb);
227 Fact* fact = instance->fact();
232 _ruleSelectIdentifierIdx = _configInstances->
count();
234 _currentSelectIdentifierValue = fact->rawValue().toInt();
237 for (
int applyIndex = 0; applyIndex < rule->
applyIdentifiers.size(); ++applyIndex) {
239 instance->setRuleApplyIdentifierIdx(applyIndex);
249 _configInstances->
append(instance);
252 for (
int i = 0; i < _configInstances->
count(); ++i) {
262 if (!_rule || _ruleSelectIdentifierIdx == -1 || _applyingRule) {
265 _applyingRule =
true;
269 const int value = selectFact->rawValue().toInt();
270 if (_rule->
items.contains(value)) {
271 bool valueChanged = value != _currentSelectIdentifierValue;
272 const auto& items = _rule->
items[value];
273 for (
int i = 0; i < _configInstances->
count(); ++i) {
277 double factValue = configInstance->
fact()->rawValue().toDouble();
278 bool changed =
false;
279 if (ruleItem.
hasMin && factValue < ruleItem.
min) {
280 factValue = ruleItem.
min;
283 if (ruleItem.
hasMax && factValue > ruleItem.
max) {
284 factValue = ruleItem.
max;
291 if (changed && !noConstraints) {
293 configInstance->
fact()->setRawValue(factValue);
302 for (
int i = 0; i < _configInstances->
count(); ++i) {
308 _currentSelectIdentifierValue = value;
310 _applyingRule =
false;
317 const auto iter = actuatorTypes.find(group.
actuatorType);
318 if (iter == actuatorTypes.end()) {
321 geometry.
index = _actuatorTypeIndex;
323 int numPositionAxis = 0;
325 for (
int i = 0; i < _configInstances->
count(); ++i) {
327 if (!configInstance->
fact()) {
330 switch (configInstance->channelConfig()->function()) {
332 geometry.
position.setX(configInstance->
fact()->rawValue().toFloat());
336 geometry.
position.setY(configInstance->
fact()->rawValue().toFloat());
340 geometry.
position.setZ(configInstance->
fact()->rawValue().toFloat());
356 return numPositionAxis == 3;
361 for (
int i = 0; i < _configInstances->
count(); ++i) {
363 if (configInstance->channelConfig()->function() ==
Function::Type) {
364 return configInstance->
fact();
372 _channelConfigs->
append(channelConfig);
378 _channels->
append(channel);
388 const QMap<int, OutputFunction>& functions,
const Rules& rules)
392 _mixerOptions = mixerOptions;
394 _functionsSpecificLabel.clear();
396 _mixerConditions.clear();
397 for (
const auto& mixerOption : _mixerOptions) {
398 _mixerConditions.append(
Condition(mixerOption.option, _parameterManager,
"mixer-option"));
407 _functionsSpecificLabel.clear();
413 for (
int i = 0; i < _mixerConditions.size(); ++i) {
414 if (_mixerConditions[i].evaluate()) {
421 if (_selectedMixer != -1) {
423 subscribeFact(_mixerConditions[_selectedMixer].fact());
425 qCDebug(ActuatorsConfigLog) <<
"selected mixer index:" << _selectedMixer;
427 const auto& actuatorGroups = _mixerOptions[_selectedMixer].actuators;
428 QMap<QString, int> actuatorTypeCount;
429 for (
const auto &actuatorGroup : actuatorGroups) {
430 int count = actuatorGroup.fixedCount;
431 if (actuatorGroup.count !=
"") {
432 Fact* countFact = getFact(actuatorGroup.count);
434 count = countFact->rawValue().toInt();
438 int actuatorTypeIndex = actuatorTypeCount.value(actuatorGroup.actuatorType, 0);
443 const auto actuatorType = _actuatorTypes.find(actuatorGroup.actuatorType);
444 if (actuatorType != _actuatorTypes.end()) {
445 for (
const auto& perItemParam : actuatorType->perItemParams) {
447 param.
param = perItemParam;
452 const Rule* selectedRule{
nullptr};
453 int axisIdx[3]{-1, -1, -1};
454 for (
const auto& perItemParam : actuatorGroup.perItemParameters) {
465 if (!perItemParam.identifier.isEmpty()) {
466 for (
const auto& rule : _rules) {
468 selectedRule = &rule;
475 if (axisIdx[0] >= 0 && axisIdx[1] >= 0 && axisIdx[2] >= 0) {
479 parameter.param.name =
"";
480 parameter.param.label = tr(
"Axis");
481 parameter.identifier =
"";
487 if (actuatorGroup.count !=
"") {
492 for (
int actuatorIdx = 0; actuatorIdx < count; ++actuatorIdx) {
494 int actuatorFunction = 0;
495 if (actuatorType != _actuatorTypes.end()) {
496 actuatorFunction = actuatorType->functionMin + actuatorTypeIndex;
497 label = _functions.value(actuatorFunction).label;
499 qCWarning(ActuatorsConfigLog) <<
"No label for output function" << actuatorFunction;
501 QString itemLabelPrefix{};
502 if (actuatorGroup.itemLabelPrefix.size() == 1) {
503 QString paramIndex = QString::number(actuatorIdx + 1);
504 itemLabelPrefix = actuatorGroup.itemLabelPrefix[0];
505 itemLabelPrefix.replace(
"${i}", paramIndex);
506 }
else if (actuatorIdx < actuatorGroup.itemLabelPrefix.size()) {
507 itemLabelPrefix = actuatorGroup.itemLabelPrefix[actuatorIdx];
509 if (itemLabelPrefix !=
"") {
510 label = itemLabelPrefix +
" (" + label +
")";
511 _functionsSpecificLabel[actuatorFunction] = itemLabelPrefix;
514 auto factAdded = [
this](
Function function,
Fact* fact) {
518 MixerChannel* channel =
new MixerChannel(currentMixerGroup, label, actuatorFunction, actuatorIdx, actuatorTypeIndex,
519 *currentMixerGroup->
channelConfigs(), _parameterManager, selectedRule, factAdded);
525 for (
const auto& parameter : actuatorGroup.parameters) {
527 parameter.label, parameter.advanced));
530 _groups->
append(currentMixerGroup);
531 actuatorTypeCount[actuatorGroup.actuatorType] = actuatorTypeIndex;
542 Fact* typeFact =
nullptr;
543 for (
int mixerGroupIdx = 0; !typeFact && mixerGroupIdx < _groups->
count(); ++mixerGroupIdx) {
545 for (
int mixerChannelIdx = 0; !typeFact && mixerChannelIdx < mixerGroup->
channels()->
count(); ++mixerChannelIdx) {
558 for (
int mixerGroupIdx = 0; mixerGroupIdx < _groups->
count(); ++mixerGroupIdx) {
560 for (
int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->
channels()->
count(); ++mixerChannelIdx) {
567 if (typeFactOther && typeFactOther->rawValue() == typeFact->rawValue()) {
568 return typeFact->enumOrValueString() +
" (" + _functions.value(function).label +
")";
572 return typeFact->enumOrValueString();
575 const auto iter = _functionsSpecificLabel.find(function);
576 if (iter == _functionsSpecificLabel.end()) {
577 return _functions.value(function).label;
585 for (
int mixerGroupIdx = 0; mixerGroupIdx < _groups->
count(); ++mixerGroupIdx) {
588 for (
int mixerChannelIdx = 0; mixerChannelIdx < mixerGroup->
channels()->
count(); ++mixerChannelIdx) {
602 if (_selectedMixer == -1) {
605 return _mixerOptions[_selectedMixer].type;
610 if (_selectedMixer == -1) {
613 return _mixerOptions[_selectedMixer].title;
617 if (_selectedMixer == -1) {
620 return _mixerOptions[_selectedMixer].helpUrl;
623Fact* Mixers::getFact(
const QString& paramName)
626 qCDebug(ActuatorsConfigLog) <<
"Mixers: Param does not exist:" << paramName;
634void Mixers::subscribeFact(
Fact* fact,
bool geometry)
637 if (fact && !_subscribedFactsGeometry.contains(fact)) {
639 _subscribedFactsGeometry.insert(fact);
642 if (fact && !_subscribedFacts.contains(fact)) {
644 _subscribedFacts.insert(fact);
649void Mixers::unsubscribeFacts()
651 for (
Fact* fact : _subscribedFacts) {
654 _subscribedFacts.clear();
656 for (
Fact* fact : _subscribedFactsGeometry) {
659 _subscribedFactsGeometry.clear();
A Fact is used to hold a single value within the system.
void rawValueChanged(const QVariant &value)
void allInstancesInitialized(QmlObjectListModel *configInstances) override
int ruleApplyIdentifierIdx() const
void setVisibleAxis(bool visible)
virtual void allInstancesInitialized(QmlObjectListModel *configInstances)
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
const QList< float > & fixedValues() const
Parameter::DisplayOption displayOption() const
virtual ChannelConfigInstance * instantiate(int paramIndex, int actuatorTypeIndex, ParameterManager *parameterManager, std::function< void(Function, Fact *)> factAddedCb)
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.
QString name
vehicle parameter name, this may have an index in the form '${i}'