85 std::cout <<
"[BTGraphLayout] Using spacing: "
121 std::cout <<
"[BTGraphLayout] Sample node positions (should be 100s-1000s of pixels):" << std::endl;
122 for (
size_t i = 0;
i < std::min(
size_t(3),
m_layouts.size()); ++
i)
126 <<
", " <<
m_layouts[
i].position.y <<
")" << std::endl;
130 std::cout <<
"[BTGraphLayout] Layout complete: " <<
m_layouts.size()
131 <<
" nodes positioned" << std::endl;
149 std::queue<std::pair<uint32_t, int>>
queue;
157 while (!
queue.empty())
159 std::pair<uint32_t, int>
front =
queue.front();
161 int layer =
front.second;
188 queue.push({childId, layer + 1});
210 for (
size_t i = 0;
i < layer.size(); ++
i)
216 m_layouts[
it->second].orderInLayer =
static_cast<int>(
i);
237 std::vector<std::pair<float, uint32_t>>
barycenters;
244 std::vector<BTNodeLayout*>
parents;
277 layer.push_back(nodeId);
281 m_layouts[
it->second].orderInLayer =
static_cast<int>(
i);
293 std::vector<std::pair<float, uint32_t>>
barycenters;
305 if (!children.empty())
336 layer.push_back(nodeId);
340 m_layouts[
it->second].orderInLayer =
static_cast<int>(
i);
348 #ifdef DEBUG_BT_LAYOUT
350 std::cout <<
"[BTGraphLayout] Edge crossings after reduction: "
363 for (
size_t i = 0;
i < layer.size(); ++
i)
382 if (layer.size() < 2)
387 auto itA = m_nodeIdToIndex.find(a);
388 auto itB = m_nodeIdToIndex.find(b);
389 if (itA == m_nodeIdToIndex.end() || itB == m_nodeIdToIndex.end())
391 return m_layouts[itA->second].position.x < m_layouts[itB->second].position.x;
395 for (
size_t i = 1;
i < layer.size(); ++
i)
424 std::vector<uint32_t> children;
429 children =
node->childIds;
434 if (
node->decoratorChildId != 0)
436 children.push_back(
node->decoratorChildId);
447 for (
const auto&
node :
tree->nodes)
509 if (children.empty())
579 for (
size_t i = 0;
i < layer.size(); ++
i)
581 for (
size_t j =
i + 1;
j < layer.size(); ++
j)
691 std::vector<std::pair<int, int>>
edges;
714 for (
size_t i = 0;
i <
edges.size(); ++
i)
716 for (
size_t j =
i + 1;
j <
edges.size(); ++
j)
Graph layout engine for behavior tree visualization.
@ Selector
OR node - succeeds if any child succeeds.
@ Sequence
AND node - succeeds if all children succeed.
@ Inverter
Decorator - inverts child result.
@ Repeater
Decorator - repeats child N times.
ComponentTypeID GetComponentTypeID_Static()
bool DoNodesOverlap(const BTNodeLayout &a, const BTNodeLayout &b, float padding) const
void ShiftSubtree(uint32_t nodeId, const BehaviorTreeAsset *tree, float offset)
const BTNodeLayout * GetNodeLayout(uint32_t nodeId) const
Get computed layout for a specific node.
void PlaceSubtree(uint32_t nodeId, const BehaviorTreeAsset *tree, int depth, float &nextAvailableX)
void ResolveCollisions(float nodeSpacingX)
std::map< uint32_t, size_t > m_nodeIdToIndex
void ApplyBuchheimWalkerLayout(const BehaviorTreeAsset *tree)
std::vector< uint32_t > GetChildren(const BTNode *node) const
void BuildParentMap(const BehaviorTreeAsset *tree)
void AssignXCoordinates(float nodeSpacingX)
BTLayoutDirection m_layoutDirection
Default vertical.
std::map< uint32_t, std::vector< uint32_t > > m_parentMap
std::vector< BTNodeLayout > ComputeLayout(const BehaviorTreeAsset *tree, float nodeSpacingX=180.0f, float nodeSpacingY=120.0f, float zoomFactor=1.0f)
Compute layout for a behavior tree.
void ReduceCrossings(const BehaviorTreeAsset *tree)
void ResolveNodeCollisionsForceDirected(float nodePadding, int maxIterations)
void PushNodeApart(uint32_t nodeA, uint32_t nodeB, float minDistance)
int CountEdgeCrossings(const BehaviorTreeAsset *tree) const
float CalculateBarycenter(uint32_t nodeId, const std::vector< BTNodeLayout * > &neighbors) const
std::vector< BTNodeLayout > m_layouts
void AssignLayers(const BehaviorTreeAsset *tree)
std::vector< std::vector< uint32_t > > m_layers
@ TopToBottom
Traditional top-down layout (vertical)
Represents a single node in a behavior tree.
Layout information for a single behavior tree node.
Vector position
Final position (x, y)
uint32_t nodeId
BT node ID.