Skip to content

Commit 23ebec8

Browse files
committedJan 23, 2024
fix issue #710
1 parent 0298470 commit 23ebec8

File tree

3 files changed

+141
-30
lines changed

3 files changed

+141
-30
lines changed
 

‎include/behaviortree_cpp/controls/switch_node.h

+58-30
Original file line numberDiff line numberDiff line change
@@ -36,47 +36,73 @@ namespace BT
3636
When the SwitchNode is executed (Switch3 is a node with 3 cases)
3737
the "variable" will be compared to the cases and execute the correct child
3838
or the default one (last).
39-
4039
*
4140
*/
41+
42+
namespace details {
43+
44+
bool CheckStringEquality(const std::string& v1, const std::string& v2,
45+
const ScriptingEnumsRegistry *enums);
46+
}
47+
4248
template <size_t NUM_CASES>
4349
class SwitchNode : public ControlNode
4450
{
4551
public:
46-
SwitchNode(const std::string& name, const BT::NodeConfig& config) :
47-
ControlNode::ControlNode(name, config), running_child_(-1)
48-
{
49-
setRegistrationID("Switch");
50-
}
52+
SwitchNode(const std::string& name, const BT::NodeConfig& config);
5153

5254
virtual ~SwitchNode() override = default;
5355

54-
void halt() override
56+
void halt() override;
57+
58+
static PortsList providedPorts();
59+
60+
private:
61+
int running_child_;
62+
std::vector<std::string> case_keys_;
63+
virtual BT::NodeStatus tick() override;
64+
};
65+
66+
//-----------------------------------------------
67+
//-----------------------------------------------
68+
69+
template<size_t NUM_CASES> inline
70+
SwitchNode<NUM_CASES>::SwitchNode(const std::string &name, const NodeConfig &config) :
71+
ControlNode::ControlNode(name, config), running_child_(-1)
72+
{
73+
setRegistrationID("Switch");
74+
for (unsigned i = 1; i <= NUM_CASES; i++)
5575
{
56-
running_child_ = -1;
57-
ControlNode::halt();
76+
case_keys_.push_back( std::string("case_") + std::to_string(i));
5877
}
78+
}
5979

60-
static PortsList providedPorts()
61-
{
80+
template<size_t NUM_CASES> inline
81+
void SwitchNode<NUM_CASES>::halt()
82+
{
83+
running_child_ = -1;
84+
ControlNode::halt();
85+
}
86+
87+
template<size_t NUM_CASES> inline
88+
PortsList SwitchNode<NUM_CASES>::providedPorts()
89+
{
90+
static PortsList ports = []() {
6291
PortsList ports;
6392
ports.insert(BT::InputPort<std::string>("variable"));
64-
for (unsigned i = 0; i < NUM_CASES; i++)
93+
for (unsigned i = 1; i <= NUM_CASES; i++)
6594
{
66-
char case_str[20];
67-
sprintf(case_str, "case_%d", i + 1);
68-
ports.insert(BT::InputPort<std::string>(case_str));
95+
auto key = std::string("case_") + std::to_string(i);
96+
ports.insert(BT::InputPort<std::string>(key));
6997
}
7098
return ports;
71-
}
99+
}();
72100

73-
private:
74-
int running_child_;
75-
virtual BT::NodeStatus tick() override;
76-
};
101+
return ports;
102+
}
77103

78-
template <size_t NUM_CASES>
79-
inline NodeStatus SwitchNode<NUM_CASES>::tick()
104+
template <size_t NUM_CASES> inline
105+
NodeStatus SwitchNode<NUM_CASES>::tick()
80106
{
81107
if (childrenCount() != NUM_CASES + 1)
82108
{
@@ -88,19 +114,21 @@ inline NodeStatus SwitchNode<NUM_CASES>::tick()
88114
std::string value;
89115
int match_index = int(NUM_CASES); // default index;
90116

91-
if (getInput("variable", variable)) // no variable? jump to default
117+
// no variable? jump to default
118+
if (getInput("variable", variable))
92119
{
93120
// check each case until you find a match
94121
for (int index = 0; index < int(NUM_CASES); ++index)
95122
{
96-
char case_key[20];
97-
sprintf(case_key, "case_%d", int(index + 1));
98-
bool found = static_cast<bool>(getInput(case_key, value));
99-
100-
if (found && variable == value)
123+
const std::string& case_key = case_keys_[index];
124+
if (getInput(case_key, value))
101125
{
102-
match_index = index;
103-
break;
126+
if(details::CheckStringEquality(
127+
variable, value, this->config().enums.get()))
128+
{
129+
match_index = index;
130+
break;
131+
}
104132
}
105133
}
106134
}

‎src/controls/switch_node.cpp

+51
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,54 @@
1111
*/
1212

1313
#include "behaviortree_cpp/controls/switch_node.h"
14+
15+
namespace BT::details
16+
{
17+
18+
bool CheckStringEquality(const std::string &v1, const std::string &v2,
19+
const ScriptingEnumsRegistry* enums)
20+
{
21+
// compare strings first
22+
if(v1 == v2)
23+
{
24+
return true;
25+
}
26+
// compare as integers next
27+
auto ToInt = [enums](const std::string& str, auto& result) -> bool
28+
{
29+
if(enums)
30+
{
31+
auto it = enums->find(str);
32+
if( it != enums->end())
33+
{
34+
result = it->second;
35+
return true;
36+
}
37+
}
38+
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
39+
return (ec == std::errc());
40+
};
41+
int v1_int = 0;
42+
int v2_int = 0;
43+
if(ToInt(v1, v1_int) && ToInt(v2, v2_int) && v1_int == v2_int)
44+
{
45+
return true;
46+
}
47+
// compare as real numbers next
48+
auto ToReal = [](const std::string& str, auto& result) -> bool
49+
{
50+
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
51+
return (ec == std::errc());
52+
};
53+
double v1_real = 0;
54+
double v2_real = 0;
55+
constexpr auto eps = double(std::numeric_limits<float>::epsilon());
56+
if(ToReal(v1, v1_real) && ToReal(v2, v2_real) &&
57+
std::abs(v1_real - v2_real) <= eps)
58+
{
59+
return true;
60+
}
61+
return false;
62+
}
63+
64+
}

‎tests/gtest_enums.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,35 @@ TEST(Enums, StrintToEnum)
8989
}
9090
}
9191

92+
TEST(Enums, SwitchNodeWithEnum)
93+
{
94+
const std::string xml_txt = R"(
95+
<root BTCPP_format="4" >
96+
<BehaviorTree ID="Main">
97+
<Sequence>
98+
<Script code=" my_color := Blue "/>
99+
<Switch4 variable="{my_color}"
100+
case_1="Red"
101+
case_2="Blue"
102+
case_3="Green"
103+
case_4="Undefined">
104+
<AlwaysFailure name="case_red" />
105+
<AlwaysSuccess name="case_blue" />
106+
<AlwaysFailure name="case_green" />
107+
<AlwaysFailure name="case_undefined" />
108+
<AlwaysFailure name="default_case" />
109+
</Switch4>
110+
</Sequence>
111+
</BehaviorTree>
112+
</root>)";
113+
114+
BehaviorTreeFactory factory;
115+
factory.registerScriptingEnums<Color>();
116+
117+
auto tree = factory.createTreeFromText(xml_txt);
118+
119+
NodeStatus status = tree.tickWhileRunning();
120+
121+
ASSERT_EQ(status, NodeStatus::SUCCESS);
122+
}
123+

0 commit comments

Comments
 (0)