2026-04-06 00:20:51 -05:00

161 lines
5.2 KiB
C++

#include <UI/Graph/LayoutTreeLeft.h>
double LayoutTreeLeft::X_SEP = 380;
double LayoutTreeLeft::Y_SEP = 160;
void LayoutTreeLeft::draw( GraphItem* item )
{
LayoutTreeLeft::NullTree( item );
LayoutTreeLeft::ReingoldTilford( item );
LayoutTreeLeft::DFS( item , 10, 0 );
}
void LayoutTreeLeft::NullTree( GraphItem* item )
{
item->Modifier = 0;
item->Thread = nullptr;
item->Ancestor = item;
for ( GraphItem* child : item->childItems)
LayoutTreeLeft::NullTree( child );
}
void LayoutTreeLeft::DFS( GraphItem* item, double m, double depth )
{
item->setPos( ( depth * X_SEP ) + 100, item->Prelim + m );
for ( GraphItem* child : item->childItems )
LayoutTreeLeft::DFS( child, m + item->Modifier, depth + 1 );
}
void LayoutTreeLeft::ReingoldTilford( GraphItem* item )
{
if ( item->childItems.empty() ) {
if ( item->parentItem && item != item->parentItem->childItems[0] ) {
QVector<GraphItem*> children = item->parentItem->childItems;
GraphItem* sibling = *std::prev( std::ranges::find(std::as_const(children), item ) );
item->Prelim = sibling->Prelim + Y_SEP;
} else {
item->Prelim = 0;
}
} else {
GraphItem* defaultAncestor = item->childItems[ 0 ];
for(int i=0; i < item->childItems.size(); i++ ) {
GraphItem* child = item->childItems[i];
LayoutTreeLeft::ReingoldTilford( child );
LayoutTreeLeft::apportion( child, defaultAncestor );
}
LayoutTreeLeft::executeShifts( item );
const double midpoint = ( item->childItems[ 0 ]->Prelim + item->childItems.back()->Prelim ) / 2;
if ( item->parentItem && item != item->parentItem->childItems[ 0 ] ) {
QVector<GraphItem*> children = item->parentItem->childItems;
GraphItem* sibling = *std::prev( std::ranges::find(std::as_const(children), item ) );
item->Prelim = sibling->Prelim + Y_SEP;
item->Modifier = item->Prelim - midpoint;
} else {
item->Prelim = midpoint;
}
}
}
void LayoutTreeLeft::apportion( GraphItem* item, GraphItem*& defaultAncestor )
{
if ( item != item->parentItem->childItems[ 0 ] ) {
QVector<GraphItem*> children = item->parentItem->childItems;
GraphItem* sibling = *std::prev( std::ranges::find(std::as_const(children), item ) );
GraphItem* vip = item;
GraphItem* vop = item;
GraphItem* vim = sibling;
GraphItem* vom = vip->parentItem->childItems[ 0 ];
double sip = vip->Modifier;
double sop = vop->Modifier;
double sim = vim->Modifier;
double som = vom->Modifier;
while ( LayoutTreeLeft::nextRight( vim ) && LayoutTreeLeft::nextLeft( vip ) ) {
vim = LayoutTreeLeft::nextRight( vim );
vip = LayoutTreeLeft::nextLeft( vip );
vom = LayoutTreeLeft::nextLeft( vom );
vop = LayoutTreeLeft::nextRight( vop );
vop->Ancestor = item;
double shift = ( vim->Prelim + sim ) - ( vip->Prelim + sip ) + Y_SEP;
if ( shift > 0 ) {
LayoutTreeLeft::moveSubtree( LayoutTreeLeft::ancestor( vim, item, defaultAncestor ), item, shift );
sip += shift;
sop += shift;
}
sim += vim->Modifier;
sip += vip->Modifier;
som += vom->Modifier;
sop += vop->Modifier;
}
if ( LayoutTreeLeft::nextRight( vim ) && ! LayoutTreeLeft::nextRight( vop ) ) {
vop->Thread = LayoutTreeLeft::nextRight( vim );
vop->Modifier += sim - sop;
}
if ( LayoutTreeLeft::nextLeft( vip ) && ! LayoutTreeLeft::nextLeft( vom ) ) {
vom->Thread = nextLeft( vip );
vom->Modifier += sip - som;
defaultAncestor = item;
}
}
}
GraphItem* LayoutTreeLeft::nextRight(GraphItem* item)
{
return ( !item->childItems.empty() ) ? item->childItems.back() : item->Thread;
}
GraphItem* LayoutTreeLeft::nextLeft(GraphItem* item)
{
return ( !item->childItems.empty() ) ? item->childItems[0] : item->Thread;
}
GraphItem* LayoutTreeLeft::ancestor(const GraphItem* vim, const GraphItem* v, GraphItem*& defaultAncestor )
{
return (vim->Ancestor->parentItem == v->parentItem) ? vim->Ancestor : defaultAncestor;
}
void LayoutTreeLeft::executeShifts( GraphItem* item )
{
double shift = 0;
double change = 0;
for ( int i = item->childItems.size() - 1; i >= 0; i-- ) {
GraphItem* child = item->childItems[i];
child->Prelim += shift;
child->Modifier += shift;
change += child->Change;
shift += child->Shift + change;
}
}
void LayoutTreeLeft::moveSubtree( GraphItem* wm, GraphItem* wp, double shift)
{
QVector<GraphItem*> children = wm->parentItem->childItems;
auto wmIndex = std::distance( children.cbegin(), std::ranges::find(std::as_const(children), wm ) );
auto wpIndex = std::distance( children.cbegin(), std::ranges::find(std::as_const(children), wp ) );
int subtrees = wpIndex - wmIndex;
if ( subtrees != 0 ) {
wp->Change -= shift / subtrees;
wp->Shift += shift;
wm->Change += shift / subtrees;
wp->Prelim += shift;
wp->Modifier += shift;
}
}